(一)什么是Mybatis
MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以对配置和原生Map使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
(二)Hebernate和Mybatis的区别
- hibernate是全自动,但mybatis是半自动。hibernate完全可以通过对象关系模型实现对数据库的操作,拥有完整的JavaBean对象与数据库的映射结构来自动生成sql,而mybatis仅有基本的字段映射,对象数据以及对象实际关系仍然需要通过手写sql来实现和管理。Mybatis可以配置动态SQL并优化SQL,通过配置决定SQL的映射规则,它还支持存储过程等。对于一些复杂的和需要优化性能的项目,使用Mybatis更加合适。
- hibernate数据库移植性远大于mybatis。hibernate通过它强大的映射结构和hql语言,大大降低了对象与数据库(oracle、mysql等)的耦合性,而mybatis由于需要手写sql,因此与数据库的耦合性直接取决于程序员写sql的方法,如果sql不具通用性而用了很多某数据库特性的sql语句的话,移植性也会随之降低很多,成本很高。
- hibernate拥有完整的日志系统,mybatis则欠缺一些。hibernate日志系统非常健全,涉及广泛,包括:sql记录、关系异常、优化警告、缓存提示、脏数据警告等;而mybatis则除了基本记录功能外,功能薄弱很多。
(三)MyBatis的优缺点
1.优点
- 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
- 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql基本上可以实现我们不使用数据访问框架可以实现的所有功能,或许更多。
- 解除sql与程序代码的耦合:通过提供DAL层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
- 提供映射标签,支持对象与数据库的orm字段关系映射
- 提供对象关系映射标签,支持对象关系组建维护
- 提供xml标签,支持编写动态sql。
2.缺点
- 编写SQL语句时工作量很大,尤其是字段多、关联表多时,更是如此。
- SQL语句依赖于数据库,导致数据库移植性差,不能更换数据库。
- 框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写,工作量也比较大,而且不太容易适应快速数据库修改。
- 二级缓存机制不佳
(三)Mybatis工作原理
如图所示:
Mybatis操作数据执行步骤:
1.SqlMapConfig.xml:是Mybatis全局配置文件,配置Mybatis运行环境等信息,主要用来配置数据库连接。
2.Mapper.xml映射文件:Mapper.xml文件即是SQL映射文件,该文件配置操作数据库的SQL语句,需要在SqlMapConfig.xml中加载才能执行。SqlMapConfig.xml可以加载多个配置文件,每个配置文件对应数据库中的一张表。
3.构造会话工厂SqlSessionFactory :通过SqlMapConfig.xml配置文件构建SqlSessionFactory对象。
4.创建SqlSession对象:通过会话工厂创建SqlSession对象,SqlSession对象用来操作数据库。
5.Excutor执行器:用来根据SqlSession传递的传参数动态的生成需要执行的SQL语句,同时负责查询缓存的维护。
6.MapperStatement对象:在执行Excutor接口的执行方法,包含一个MapperStatement类型的参数,该参数是对映射信息的封装,用于存储要映射的SQL语句的id、参数等等。Mapper.xml文件中的一个SQL语句对应一个MapperStatement对象,SQL的id就是MapperStatement的id.
7.输入参数映射。在执行方法时,MapperStatement对象会对用户执行SQL语句的输入参数进行定义,Exceutor执行器会通过MapperStatement对象在执行SQL前,将输入的Java对象映射到SQL语句中,这里对输入参数的映射类似JDBC编程中对preparedStatement对象设置参数的过程。
8.输出结果映射。在执行方法时,MapperStatement对象会对用户执行SQL语句的输出参数进行定义,Exceutor执行器会通过MapperStatement对象在执行SQL后,将输出结果映射到Java对象中,这里对输出结果映射到Java对象的过程雷士JBDC编程中对结果的解析处理过程。
(四)Mybatis实现对数据库的增删查改
Mybatis下载及使用
项目结构图
1.创建数据表
CREATE TABLE `t_customer` (
`id` int(32) NOT NULL AUTO_INCREMENT,
`username` varchar(50) DEFAULT NULL,
`jobs` varchar(50) DEFAULT NULL,
`phone` varchar(16) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
INSERT INTO `t_customer` VALUES ('1', 'joy', 'doctor', '18990123432');
INSERT INTO `t_customer` VALUES ('2', 'jack', 'teacher', '18992823439');
INSERT INTO `t_customer` VALUES ('3', 'tom', 'student', '18390912376');
2.在项目的src文件夹下创建log4j.properties用于在控制台查看日志信息
# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.com.wang=DEBUG
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
3.在com.wang.po包下创建Customer.java
package com.wang.po;
public class Customer {
private Integer id;
private String username;
private String jobs;
private String phone;
----省略setter和getter----
@Override
public String toString() {
return "Customer [id=" + id + ", username=" + username +
", jobs=" + jobs + ", phone=" + phone + "]";
}
}
3.在com.wang.mapper包下创建CustomerMapper.xml用于配置SQL语句
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace表示命名空间=(包名+映射文件名) -->
<mapper namespace="com.wang.mapper.CustomerMapper">
<!--1.根据客户编号获取客户信息 -->
<select id="findCustomerById" parameterType="Integer"
resultType="com.wang.po.Customer">
select*from t_customer where id=#{id}
</select>
<!--1.根据客户名查询客户 -->
<select id="findCustomerByName" parameterType="String"
resultType="com.wang.po.Customer">
select*from t_customer where username like concat('%',#{username},'%')
</select>
<!--2.添加客户 -->
<insert id="addCustomer" parameterType="com.wang.po.Customer">
insert into t_customer(username,jobs,phone)values(#{username},
#{jobs},#{phone})
</insert>
<!--3.修改用户信息 -->
<update id="updateCustomer" parameterType="com.wang.po.Customer">
update t_customer set username=#{username},jobs=#{jobs}
,phone=#{phone} where id=#{id}
</update>
<!--4.删除用户-->
<delete id="deleteCustomer" parameterType="Integer">
delete from t_customer where id=#{id}
</delete>
</mapper>
注:#{}和${}的区别是什么?
#{}是预编译处理,${}是字符串替换。
Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值
Mybatis在处理${}时,就是把${}替换成变量的值。
使用#{}可以有效的防止SQL注入,提高系统安全性。
注:模糊查询like语句该怎么写?
方法01:使用Mysql中的concat()函数进行字符串拼接
select*from t_customer where username like concat('%',#{username},'%')
4.在Src文件夹下创建mybatis-config.xml用于配置连接数据库的信息
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--1.配置环境 ,默认的环境id为mysql-->
<environments default="mysql">
<!--1.2.配置id为mysql的数据库环境 -->
<environment id="mysql">
<!-- 使用JDBC的事务管理 -->
<transactionManager type="JDBC" />
<!--数据库连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost:3306/mybatis" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
<!--2.配置Mapper的位置 -->
<mappers>
<!--配置com.wang.mapper包下的CustomerMapper.xml -->
<mapper resource="com/wang/mapper/CustomerMapper.xml" />
</mappers>
</configuration>
5.在com.wang.Test包下创建MybatisTest.java
注:
01.执行数据库|查询|:不需要提交事务
02.执行数据库|添加|删除|修改|等操作:需要提交事务
package com.wang.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import com.wang.po.Customer;
public class MybatisTest {
@Test
public void findCustomerById() throws Exception {
// 1、读取配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 2、根据配置文件构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 3、通过SqlSessionFactory创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 4、SqlSession执行映射文件中定义的SQL,并返回映射结果
Customer customer = sqlSession.selectOne("com.wang.mapper" + ".CustomerMapper.findCustomerById", 1);
// 打印输出结果
System.out.println(customer.toString());
// 5、关闭SqlSession
sqlSession.close();
}
@Test
public void findCustomerByName() throws IOException { // 1、读取配置文件
// 1、读取配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 2、根据配置文件构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 3、通过SqlSessionFactory创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
List<Customer> customers = sqlSession.selectList("com.wang.mapper.CustomerMapper.findCustomerByName", "j");
for (Customer customer : customers) {
System.out.println(customer);
}
// 5、关闭SqlSession
sqlSession.close();
}
@Test
public void addCustomer() throws IOException {
// 1、读取配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 2、根据配置文件构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 3、通过SqlSessionFactory创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 创建customer封装数据
Customer customer = new Customer();
customer.setUsername("rose");
customer.setJobs("student");
customer.setPhone("18390994116");
int rows = sqlSession.insert("com.wang.mapper.CustomerMapper.addCustomer", customer);
if (rows > 0) {
System.out.println("插入" + rows + "条数据");
} else {
System.out.println("数据插入失败!");
}
// 4.必须提交事务,否则数据无法插入到数据库
sqlSession.commit();
sqlSession.close();
}
@Test
public void updateCustomer() throws IOException {
// 1、读取配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 2、根据配置文件构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 3、通过SqlSessionFactory创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 创建customer封装数据
Customer customer = new Customer();
customer.setId(5);
customer.setUsername("rose01");
customer.setJobs("student");
customer.setPhone("18390994116");
int rows = sqlSession.update("com.wang.mapper.CustomerMapper.updateCustomer", customer);
if (rows > 0) {
System.out.println("已经修改" + rows + "条数据");
} else {
System.out.println("数据修改失败!");
}
// 4.必须提交事务,否则数据无法插入到数据库
sqlSession.commit();
sqlSession.close();
}
@Test
public void deleteCustomer() throws IOException {
// 1、读取配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 2、根据配置文件构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 3、通过SqlSessionFactory创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
int rows = sqlSession.update("com.wang.mapper.CustomerMapper.deleteCustomer", 5);
if (rows > 0) {
System.out.println("已经删除" + rows + "条数据");
} else {
System.out.println("数据删除失败!");
}
// 4.必须提交事务,否则数据无法插入到数据库
sqlSession.commit();
sqlSession.close();
}
}
(五)使用工具类创建SqlSession对象
使用工具类:提取公共代码封装在工具类中,目的简化代码的开发,提高编程效率。
package com.wang.utils;
import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
/**
* 工具类
*/
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory = null;
// 初始化SqlSessionFactory对象
static {
try {
// 使用MyBatis提供的Resources类加载MyBatis的配置文件
Reader reader =
Resources.getResourceAsReader("mybatis-config.xml");
// 构建SqlSessionFactory工厂
sqlSessionFactory =
new SqlSessionFactoryBuilder().build(reader);
} catch (Exception e) {
e.printStackTrace();
}
}
// 获取SqlSession对象的静态方法
public static SqlSession getSession() {
return sqlSessionFactory.openSession();
}
}