MyBatis
基本介绍
ORM(Object Relational Mapping): 对象关系映射,指的是持久化数据和实体对象的映射模式,解决面向对象与关系型数据库存在的互不匹配的现象

MyBatis:
-
MyBatis 是一个优秀的基于 Java 的持久层框架,它内部封装了 JDBC,使开发者只需关注 SQL 语句本身,而不需要花费精力去处理加载驱动、创建连接、创建 Statement 等过程。
-
MyBatis 通过 XML 或注解的方式将要执行的各种 Statement 配置起来,并通过 Java 对象和 Statement 中 SQL 的动态参数进行映射生成最终执行的 SQL 语句。
-
MyBatis 框架执行 SQL 并将结果映射为 Java 对象并返回。采用 ORM 思想解决了实体和数据库映射的问题,对 JDBC 进行了封装,屏蔽了 JDBC 底层 API 的调用细节,使我们不用操作 JDBC API,就可以完成对数据库的持久化操作。
MyBatis 官网地址:http://www.mybatis.org/mybatis-3/
参考视频:https://space.bilibili.com/37974444/
基本操作
相关API
Resources:加载资源的工具类
InputStream getResourceAsStream(String fileName):通过类加载器返回指定资源的字节流- 参数 fileName 是放在 src 的核心配置文件名:MyBatisConfig.xml
SqlSessionFactoryBuilder:构建器,用来获取 SqlSessionFactory 工厂对象
SqlSessionFactory build(InputStream is):通过指定资源的字节输入流获取 SqlSession 工厂对象
SqlSessionFactory:获取 SqlSession 构建者对象的工厂接口
SqlSession openSession():获取 SqlSession 构建者对象,并开启手动提交事务SqlSession openSession(boolean):获取 SqlSession 构建者对象,参数为 true 开启自动提交事务
SqlSession:构建者对象接口,用于执行 SQL、管理事务、接口代理
- SqlSession 代表和数据库的一次会话,用完必须关闭
- SqlSession 和 Connection 一样都是非线程安全,每次使用都应该去获取新的对象
注:update 数据需要提交事务,或开启默认提交
SqlSession 常用 API:
| 方法 | 说明 |
|---|---|
| List | 执行查询语句,返回List集合 |
| T selectOne(String statement,Object parameter) | 执行查询语句,返回一个结果对象 |
| int insert(String statement,Object parameter) | 执行新增语句,返回影响行数 |
| int update(String statement,Object parameter) | 执行删除语句,返回影响行数 |
| int delete(String statement,Object parameter) | 执行修改语句,返回影响行数 |
| void commit() | 提交事务 |
| void rollback() | 回滚事务 |
| T getMapper(Class | 获取指定接口的代理实现类对象 |
| void close() | 释放资源 |
映射配置
映射配置文件包含了数据和对象之间的映射关系以及要执行的 SQL 语句,放在 src 目录下
命名:StudentMapper.xml
-
映射配置文件的文件头:
<?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:属性,名称空间
-
功能标签:
- < select >:查询功能标签
:新增功能标签 :修改功能标签 :删除功能标签 - id:属性,唯一标识,配合名称空间使用
- resultType:指定结果映射对象类型,和对应的方法的返回值类型(全限定名)保持一致,但是如果返回值是 List 则和其泛型保持一致
- parameterType:指定参数映射对象类型,必须和对应的方法的参数类型(全限定名)保持一致
- statementType:可选 STATEMENT,PREPARED 或 CALLABLE,默认值:PREPARED
- STATEMENT:直接操作 SQL,使用 Statement 不进行预编译,获取数据:$
- PREPARED:预处理参数,使用 PreparedStatement 进行预编译,获取数据:#
- CALLABLE:执行存储过程,CallableStatement
-
参数获取方式:
-
SQL 获取参数:
#{属性名}<mapper namespace="StudentMapper">
<select id="selectById" resultType="student" parameterType="int">
SELECT * FROM student WHERE id = #{id}
</select>
<mapper/>
-
强烈推荐官方文档:https://mybatis.org/mybatis-3/zh/sqlmap-xml.html
核心配置
核心配置文件包含了 MyBatis 最核心的设置和属性信息,如数据库的连接、事务、连接池信息等
命名:MyBatisConfig.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"> -
根标签:
:核心根标签
-
引入连接配置文件:
-
: 引入数据库连接配置文件标签 - resource:属性,指定配置文件名
<properties resource="jdbc.properties"/>
-
-
调整设置
:可以改变 Mybatis 运行时行为
-
起别名:
-
:为全类名起别名的父标签 -
:为全类名起别名的子标签 - type:指定全类名
- alias:指定别名
-
:为指定包下所有类起别名的子标签,别名就是类名,首字母小写
<!--起别名-->
<typeAliases>
<typeAlias type="bean.Student" alias="student"/>
<package name="com.seazean.bean"/>
<!--二选一-->
</typeAliase> -
-
自带别名:
别名 数据类型 string java.lang.String long java.lang.Lang int java.lang.Integer double java.lang.Double boolean java.lang.Boolean .... ......
-
-
配置环境,可以配置多个标签
:配置数据库环境标签,default 属性指定哪个 environment :配置数据库环境子标签,id 属性是唯一标识,与 default 对应 :事务管理标签,type 属性默认 JDBC 事务 :数据源标签 - type 属性:POOLED 使用连接池(MyBatis 内置),UNPOOLED 不使用连接池
:数据库连接信息标签。 - name 属性取值:driver,url,username,password
- value 属性取值:与 name 对应
-
引入映射配置文件
:引入映射配置文件标签 :引入映射配置文件子标签 - resource:属性指定映射配置文件的名称
- url:引用网路路径或者磁盘路径下的 sql 映射文件
- class:指定映射配置类
:批量注册
参考官方文档:https://mybatis.org/mybatis-3/zh/configuration.html
#{}和${}
#{}:占位符,传入的内容会作为字符串加上引号,以预编译的方式传入,将 sql 中的 #{} 替换为 ? 号,调用 PreparedStatement 的 set 方法来赋值,有效的防止 SQL 注入,提高系统安全性
${}:拼接符,传入的内容会直接替换拼接,不会加上引号,可能存在 sql 注入的安全隐患
-
能用 #{} 的地方就用 #{},不用或少用 ${}
-
必须使用 ${} 的情况:
- 表名作参数时,如:
SELECT * FROM ${tableName} - order by 时,如:
SELECT * FROM t_user ORDER BY ${columnName}
- 表名作参数时,如:
-
sql 语句使用 #{},properties 文件内容获取使用 ${}
日志文件
在日常开发过程中,排查问题时需要输出 MyBatis 真正执行的 SQL 语句、参数、结果等信息,就可以借助 log4j 的功能来实现执行信息的输出。
-
在核心配置文件根标签内配置 log4j
<!--配置LOG4J-->
<settings>
<setting name="logImpl" value="log4j"/>
</settings> -
在 src 目录下创建 log4j.properties
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# 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
#输出到日志文件
#log4j.appender.file=org.apache.log4j.FileAppender
#log4j.appender.file.File=../logs/iask.log
#log4j.appender.file.layout=org.apache.log4j.PatternLayout
#log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %l %m%n -
pom.xml
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
代码实现
-
实体类
public class Student {
private Integer id;
private String name;
private Integer age;
.....
} -
StudentMapper
public interface StudentMapper {
//查询全部
public abstract List<Student> selectAll();
//根据id查询
public abstract Student selectById(Integer id);
//新增数据
public abstract Integer insert(Student stu);
//修改数据
public abstract Integer update(Student stu);
//删除数据
public abstract Integer delete(Integer id);
} -
config.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://192.168.2.184:3306/db1
username=root
password=123456 -
MyBatisConfig.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>
<!--引入数据库连接的配置文件-->
<properties resource="jdbc.properties"/>
<!--配置LOG4J-->
<settings>
<setting name="logImpl" value="log4j"/>
</settings>
<!--起别名-->
<typeAliases>
<typeAlias type="bean.Student" alias="student"/>
<!--<package name="bean"/>-->
</typeAliases>
<!--配置数据库环境,可以多个环境,default指定哪个-->
<environments default="mysql">
<!--id属性唯一标识-->
<environment id="mysql">
<!--事务管理,type属性,默认JDBC事务-->
<transactionManager type="JDBC"></transactionManager>
<!--数据源信息 type属性连接池-->
<dataSource type="POOLED">
<!--property获取数据库连接的配置信息-->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!--引入映射配置文件-->
<mappers>
<!--mapper引入指定的映射配置 resource属性执行的映射配置文件的名称-->
<mapper resource="StudentMapper.xml"/>
</mappers>
</configuration> -
StudentMapper.xml
<?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">
<mapper namespace="StudentMapper">
<select id="selectAll" resultType="student">
SELECT * FROM student
</select>
<select id="selectById" resultType="student" parameterType="int">
SELECT * FROM student WHERE id = #{id}
</select>
<insert id="insert" parameterType="student">
INSERT INTO student VALUES (#{id},#{name},#{age})
</insert>
<update id="update" parameterType="student">
UPDATE student SET name = #{name}, age = #{age} WHERE id = #{id}
</update>
<delete id="delete" parameterType="student">
DELETE FROM student WHERE id = #{id}
</delete>
</mapper> -
控制层测试代码:根据 id 查询
@Test
public void selectById() throws Exception{
//1.加载核心配置文件
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
//2.获取SqlSession工厂对象
SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(is);
//3.通过工厂对象获取SqlSession对象
SqlSession sqlSession = ssf.openSession();
//4.执行映射配置文件中的sql语句,并接收结果
Student stu = sqlSession.selectOne("StudentMapper.selectById", 3);
//5.处理结果
System.out.println(stu);
//6.释放资源
sqlSession.close();
is.close();
} -
控制层测试代码:新增功能
@Test
public void insert() throws Exception{
//1.加载核心配置文件
//2.获取SqlSession工厂对象
//3.通过工厂对象获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//4.执行映射配置文件中的sql语句,并接收结果
Student stu = new Student(5, "周七", 27);
int result = sqlSession.insert("StudentMapper.insert", stu);
//5.提交事务
//sqlSession.commit();
//6.处理结果
System.out.println(result);
//7.释放资源
sqlSession.close();
is.close();
}
批量操作
三种方式实现批量操作:
-
标签属性:这种方式属于全局批量 <settings>
<setting name="defaultExecutorType" value="BATCH"/>
</settings>defaultExecutorType:配置默认的执行器
- SIMPLE 就是普通的执行器(默认,每次执行都要重新设置参数)
- REUSE 执行器会重用预处理语句(只预设置一次参数,多次执行)
- BATCH 执行器不仅重用语句还会执行批量更新(只针对修改操作)
-
SqlSession 会话内批量操作:
public void testBatch() throws IOException{
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
// 可以执行批量操作的sqlSession
SqlSession openSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
long start = System.currentTimeMillis();
try{
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
for (int i = 0; i < 10000; i++) {
mapper.addEmp(new Employee(UUID.randomUUID().toString().substring(0, 5), "b", "1"));
}
openSession.commit();
long end = System.currentTimeMillis();
// 批量:(预编译sql一次==>设置参数===>10000次===>执行1次(类似管道))
// 非批量:(预编译sql=设置参数=执行)==》10000 耗时更多
System.out.println("执行时长:" + (end - start));
}finally{
openSession.close();
}
} -
Spring 配置文件方式(applicationContext.xml):
<!--配置一个可以进行批量执行的sqlSession -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactoryBean"/>
<constructor-arg name="executorType" value="BATCH"/>
</bean>@Autowired
private SqlSession sqlSession;