mybatis基础知识总结
一、软件开发常用结构
1.1 三层架构
界面层: 和用户打交道的, 接收用户的请求参数, 显示处理结果的。(jsp ,html ,servlet)用户看到的界面。
业务逻辑层: 接收了界面层传递的数据,计算逻辑,调用数据库,获取数据。(完成相关的业务逻辑)
数据访问层: 就是访问数据库, 执行对数据的查询,修改,删除等等的。
三层对应的包
界面层: controller包 (servlet)
业务逻辑层: service 包(XXXService类)
数据访问层: dao包(XXXDao类)
三层中类的交互
用户使用界面层--> 业务逻辑层--->数据访问层(持久层)-->数据库(mysql)
在spring框架中,三层对应的处理框架
界面层---servlet---springmvc(框架)
业务逻辑层---service类--spring(框架)
数据访问层---dao类--mybatis(框架)---->代替JDBC
为什么要使用三层?
- 结构清晰、耦合度低, 各层分工明确(界面与逻辑代码分离开)
- 可维护性高,可扩展性高
- 有利于标准化
- 开发人员可以只关注整个结构中的其中某一层的功能实现
- 有利于各层逻辑的复用
1.2 框架
简单的说,框架其实就是半成品软件(模板),就是一组组件,供你快速搭建你的系统,在框架基础上加入你要完成的功能。另外,框架是安全的,可复用的,不断升级的软件。
框架是一个模块
- 框架中定义好了一些功能。这些功能是可用的。
- 可以在项目中加入自己的功能, 这些功能可以利用框架中写好的功能。
框架特点:
- 框架一般不是全能的, 不能做所有事情
- 框架是针对某一个领域有效。 特长在某一个方面,比如mybatis做数据库操作强,但是他不能做其它的。
- 框架是一个软件
1.1.1 回顾 JDBC 编程
jdbc代码:
package com.xzz;
import com.xzz.domain.Student;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
public class a {
@Test
public void findStudent() {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
//注册 mysql 驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//连接数据的基本信息 url ,username,password
String url = "jdbc:mysql://localhost:3306/student?characterEncoding=utf8&useSSL=false&serverTimezone = UTC";
String username = "root";
String password = "123456";
//创建连接对象
conn = DriverManager.getConnection(url, username, password);
//保存查询结果
List<Student> stuList = new ArrayList<>();
//创建 Statement, 用来执行 sql 语句
stmt = conn.createStatement();
//执行查询,创建记录集,
rs = stmt.executeQuery("select * from student");
while (rs.next()) {
Student stu = new Student();
stu.setId(rs.getInt("id"));
stu.setName(rs.getString("name"));
stu.setAge(rs.getInt("age"));
//从数据库取出数据转为 Student 对象,封装到 List 集合
stuList.add(stu);
}
System.out.println("查询结果:"+ "\n"+stuList);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
//关闭资源
if (rs != null){
rs.close();
}
if (stmt != null) {
stmt.close();
}
if (conn != null) {
conn.close();
}
}catch (Exception e) {
e.printStackTrace();
}
}
}
}
1.1.2 使用 JDBC 的缺陷
- 代码比较多,开发效率低
- 需要关注 Connection ,Statement, ResultSet 对象创建和销毁
- 对 ResultSet 查询的结果,需要自己封装为 List
- 重复的代码比较多些
- 业务代码和数据库的操作混在一起
1.3 mybatis框架
一个操作数据库的框架,早期叫做ibatis, 代码在github。mybatis是 MyBatis SQL Mapper Framework for Java (sql映射框架),是一个基于 Java 的持久层框架。
1)sql mapper :sql映射可以把数据库表中的一行数据映射为一个java对象。一行数据可以看做是一个java对象。操作这个对象,就相当于操作表中的数据。
2) Data Access Objects(DAOs) : 数据访问 , 对数据库执行增删改查。
mybatis提供了哪些功能:
- 提供了创建Connection ,Statement, ResultSet的能力 ,不用开发人员创建这些对象
- 提供了执行sql语句的能力, 不用你执行sql
- 提供了循环sql,把sql的结果转为java对象, List集合的能力。不需要开发人员手动去写下列的代码。
while (rs.next()) {
Student stu = new Student();
stu.setId(rs.getInt("id"));
stu.setName(rs.getString("name"));
stu.setAge(rs.getInt("age"));
//从数据库取出数据转为 Student 对象,封装到 List 集合
stuList.add(stu);
}
- 提供了关闭资源的能力,不用你关闭Connection, Statement, ResultSet。
开发人员做的是: 提供sql语句,mybatis自动处理sql,并得到List集合或java对象(表中的数据)
总结:
- mybatis是一个sql映射框架,提供了数据库的操作能力,是增强的JDBC。
- 使用mybatis让开发人员关注写sql就可以了,不必关心Connection,Statement,ResultSet 的创建,销毁以及sql的执行、处理返回结果。这些工作由mybatis自动处理完成。
二、MyBatis 框架快速入门
搭建mybatis开发环境:
-
创建mysql数据库和表
-
创建Maven工程
-
加入相关依赖
-
加入maven插件
-
编写实体类
-
编写Dao接口,定义方法
-
编写Dao接口对应的mapper文件
-
创建mybatis主配置文件
-
创建测试类,测试mapper文件里面的方法
-
配置日志功能(可选)
2.1 主要类的介绍
1) Resources: mybatis中的一个类, 负责读取主配置文件
InputStream in = Resources.getResourceAsStream(“mybatis.xml”);
2) SqlSessionFactoryBuilder : 创建SqlSessionFactory对象。
//创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//创建SqlSessionFactory对象
SqlSessionFactory factory = builder.build(in);
3)SqlSessionFactory : 重量级对象, 程序创建这一个对象耗时比较长,使用资源比较多。在整个项目中,有一个就够用了。
SqlSessionFactory:接口 , 接口实现类: DefaultSqlSessionFactory
SqlSessionFactory作用: 获取SqlSession对象。SqlSession sqlSession = factory.openSession();
SqlSession中的openSession()方法说明:
1.openSession() :无参数的, 获取是非自动提交事务的SqlSession对象
2.openSession(boolean): openSession(true) 获取自动提交事务的SqlSession.
openSession(false) 非自动提交事务的SqlSession对象
4)SqlSession:
SqlSession接口 :定义了操作数据库的方法,例如 selectOne() ,selectList() ,insert(),update(), delete(), commit(), rollback()等与操作数据库有关的方法。 SqlSession接口的实现类DefaultSqlSession。
注意:
- 使用要求: SqlSession对象不是线程安全的,需要在方法内部使用, 在执行sql语句之前,使用openSession()获取SqlSession对象。
- 在执行完sql语句后,需要关闭它,执行SqlSession.close(). 这样能保证他的使用是线程安全的。
2.2 工具类的使用
为什么要使用工具类,我们先来看看没有使用工具类的情况下,实现的代码:
我们可以看到,在执行SQL语句前,需要引入mybatis配置文件,以及创建可以执行SQL语句的对象,这些操作在以后的各个业务方法中都是必要的,且重复的。为了让这些代码能够在多个业务方法中能够复用,我们可以将这部分可重复使用的代码抽离到一个文件中,再要使用的地方在调用即可,减少冗余的代码,提高性能,也提高程序的可读性。
2.2.1 创建 MyBatisUtil 类
2.3 传统的DAO使用方式
使用 Dao 的实现类,操作数据库
2.3.1 创建 Dao 接口实现类
在该类中实现接口中的方法,这里展示select方法。
测试方法:
2.3.2 传统 Dao 开发方式的分析
从前面例子中可以看出,自定义 Dao 的实现类仅仅就是通过 SqlSession 的相关 API 定位到映射文件 mapper 中相应 id 的 SQL 语句,真正对 DB 进行操作的工作其实是由框架通过 mapper 中的 SQL 完成的。所以,MyBatis 框架就抛开了 Dao 的实现类,直接定位到映射文件 mapper 中的相应 SQL 语句,对DB 进行操作。这种对 Dao 的实现方式称为 Mapper 的动态代理方式。Mapper 动态代理方式无需程序员实现 Dao 接口。接口是由 MyBatis 结合映射文件自动生成的动态代理实现的。
2.4 使用动态代理的条件
对传统的DAO进行分析:
List<Student> studentList = dao.selectStudents(); 调用
1.dao对象,类型是StudentDao,全限定名称是:com.xzz.dao.StudentDao
全限定名称 和 namespace 是一样的。
2.方法名称, selectStudents, 这个方法就是 mapper文件中的 id值 selectStudents
通过dao.selectStudents就相当于找到mapper文件中对应的SQL语句,这也就相当于StudentDaoImpl里面对应的sqlId。所以mybatis可以通过这条链路知道要执行select方法还是insert方法。
3.通过dao中方法的返回值也可以确定MyBatis要调用的SqlSession的方法
如果返回值是List ,调用的是SqlSession.selectList()方法。
如果返回值 int ,或是非List的, 看mapper文件中的 标签是<insert>,<update> 就会调用
SqlSession的insert, update等方法
mybatis的动态代理: mybatis根据 dao的方法调用,获取执行sql语句的信息。
mybatis根据你的dao接口,创建出一个dao接口的实现类, 并创建这个类的对象。
完成SqlSession调用方法, 访问数据库。
2.5 MyBatis 框架 Dao 代理
2.5.1 Dao 代理实现 CURD
步骤:
1)去掉 Dao 接口实现类
2)getMapper 获取代理对象
只需调用 SqlSession 的 getMapper()方法,即可获取指定接口的实现类对象。该方法的参数为指定 Dao接口类的 class 值。
SqlSession session = factory.openSession();
StudentDao dao = session.getMapper(StudentDao.class);
使用工具类:
StudentDao studentDao =
MyBatisUtil.getSqlSession().getMapper(StudentDao.class);
3)使用 Dao 代理对象方法执行 sql 语句
三、动态代理
动态代理: 使用SqlSession.getMapper(dao接口.class) 获取这个dao接口的对象
3.1 传入参数
从java代码中把数据传入到mapper文件的sql语句中。
3.1.1 parameterType
parameterType: 写在mapper文件中的 一个属性。 表示dao接口中方法参数的数据类型。它的值是java的数据类型全限定名称或者是mybatis定义的别名。
例如StudentDao接口
public Student selectStudentById(Integer id)
那么parameterType可以是:
parameterType="java.lang.Integer" 或 parameterType="int"
通过parameterType告诉mybatis在查询时,参数id是个整型值。
注意:parameterType不是强制的,mybatis通过反射机制能够发现接口参数的数类型。所以可以没有。 一般我们也不写。
3.1.2 一个简单类型的参数:
简单类型: mybatis把java的基本数据类型和String都叫简单类型。在mapper文件获取简单类型的一个参数的值,使用 #{任意字符}
接口:public Student selectStudentById(Integer id)
mapper:select id,name, email,age from student where id=#{studentId}
使用#{}之后, mybatis执行sql是使用jdbc中的PreparedStatement对象
由mybatis执行下面的代码:
1. mybatis创建Connection , PreparedStatement对象
String sql="select id,name, email,age from student where id=?";
PreparedStatement pst = conn.preparedStatement(sql);
pst.setInt(1,1001);
2. 执行sql封装为resultType="com.xzz.domain.Student"这个对象
ResultSet rs = ps.executeQuery();
Student student = null;
while(rs.next()){
//从数据库取表的一行数据, 存到一个java对象属性中
student = new Student();
student.setId(rs.getInt("id));
student.setName(rs.getString("name"));
student.setEmail(rs.getString("email"));
student.setAge(rs.getInt("age"));
}
return student; //赋给了dao方法调用的返回值
注意: PreparedStatement对象的优点是,效率高,速度快,防止sql注入,建议使用#作为占位符传参。
3.1.3 多个参数,使用@Param命名参数(掌握)
当 Dao 接口方法多个参数,需要通过名称使用参数。 在方法形参前面加入@Param(“自定义参数名”),mapper 文件使用#{自定义参数名}。
接口 public List<Student> selectMulitParam(@Param("myname") String name, @Param("myage") Integer age)
使用 @Param("参数名") String name
mapper文件:
<select>
select * from student where name=#{myname} or age=#{myage}
</select>
3.1.4 多个参数,使用java对象。语法 #{属性名} (掌握)
使用 java 对象传递参数时, java 的属性值就是 sql 需要的参数值。 每一个属性就是一个参数。
语法格式: #{ property,javaType=java 中数据类型名,jdbcType=数据类型名称 }
javaType, jdbcType 的类型 MyBatis 可以检测出来,一般不需要设置。
常用格式 #{ property }, javaType, jdbcType的值mybatis反射能获取,可以省略。
接口文件:
mapper 文件:
格式有以下两种,一般省略javaType=string,jdbcType=VARCHAR。
<select id="selectMultiObject" resultType="com.xzz.domain.Student">
select id,name,email,age from student where name=#{queryName} or age
=#{queryAge}
</select>
或
<select id="selectMultiObject" resultType="com.xzz.domain.Student">
select id,name,email,age from student where name=#{queryName,javaType=string,jdbcType=VARCHAR} or age =#{queryAge,javaType=int,jdbcType=INTEGER}
</select>
测试类:
vo: value object , 放一些存储数据的类。比如说 提交请求参数, name ,age
现在想把name ,age 传给一个service 类。
vo: view object , 从servlet把数据返回给浏览器使用的类,表示显示结果的类。
pojo: 普通的有set, get方法的java类。 普通的java对象
Servlet --- StudentService( addStudent( MyParam param) )
entity(domain域): 实体类, 和数据库中的表对应的类,
3.1.5 使用参数位置传参 (了解)
多个参数都是简单类型的,可按位置传值。参数位置从 0 开始, 引用参数语法 #{ arg 位置 } , 第一个参数是#{arg0}, 第二个是#{arg1}
接口 文件:
mapper文件:
测试类:
结果:
注意:mybatis-3.3 版本和之前的版本使用#{0},#{1}方式, 从 mybatis3.4 开始使用#{arg0}方式。
3.1.6 使用Map传值 (了解)
Map集合可以存储多个值,使用Map向mapper文件一次传入多个参数。Map集合使用String的key,Object 类型的值存储参数。 mapper 文件使用 # { key } 引用参数值。
接口文件:
mapper文件:
测试类:
注意: 缺点就是map中的key值是自定义的,如果map可以改了,mapper文件中的参数值位置的名字也要改,这样SQL语句和业务代码耦合度就高了。同时,map传参,也无法知道参数的类型是什么,参数有多少个,可读性差。不建议使用。
3.2 # 和 $
# :占位符,告诉 mybatis 使用实际的参数值代替。并使用 PrepareStatement 对象执行 sql 语句, #{…}代替sql 语句的“?”。这样做更安全,更迅速,通常也是首选做法。
$:字符串替换,告诉 mybatis 使用$包含的“字符串”替换所在位置。使用 Statement 把 sql 语句和${}的内容连接起来。主要用在替换表名,列名,不同列排序等操作。
1、select id,name, email,age from student where id=#{studentId}
# 的结果: select id,name, email,age from student where id=?
2、select id,name, email,age from student where id=${studentId}
$ 的结果:select id,name, email,age from student where id=1001
String sql="select id,name, email,age from student where id=" + "1001";
使用的Statement对象执行sql, 效率比PreparedStatement低。
$:可以替换表名或者列名, 或者你能确定数据是安全的可以使用$。
# 和 $区别
- #使用 ?在sql语句中做占位的, 使用的是PreparedStatement执行sql,效率高
- #能够避免sql注入,更安全。
- $不使用占位符,是字符串连接方式,使用的是Statement对象执行sql,效率低
- $有sql注入的风险,缺乏安全性。
- $:可以替换表名或者列名
3.3 mybatis的输出结果
mybatis执行了sql语句,得到java对象。
3.3.1 resultType
resultType: 结果类型, 指sql语句执行完毕后, 数据转为的java对象, java类型是任意的。
A. 简单类型
简单类型就是SQL返回的类型是简单类型的,比如说int,string等。
测试文件:
mapper文件:
像上面这种返回表中学生人数的就是简单类型。
注意:
resultType结果类型的值:
1. 类型的全限定名称 2. 类型的别名, 例如 java.lang.Integer别名是int
B. 对象类型:就是返回的类型是对象类型,例如下列测试用例中返回的是实体类Student的类型就是对象类型
测试文件:
mapper文件:
我们可以看到不管dao调用SQL语句执行后返回的是实体类类型,还是List类型,returnType都是实体类型,因为List<Student>是把SQL查询的结果按照实体类对应的属性名封装成Student类型的,然后再放到List集合里面,而不是封装成List。所以这可以看出,returnType是支持java任意类型的。也就是说,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。
处理方式:
- mybatis执行sql语句, 然后mybatis调用类的无参数构造方法,创建对象。
- mybatis把ResultSet指定列值赋给同名的属性。
简单来说:
就是使用无参构造方法创建对象,然后调用 setXXX 给属性赋值。
Student student = new Student();
sql语句列 | java 对象方法 | |
id | setId( rs.getInt(“id”) ) | 调用列名对应的 set 方法 id 列 --- setId() name 列 --- setName() |
name | setName( rs.getString(“name”) ) | |
setEmail( rs.getString(“email”) ) | ||
age | setAge( rs.getInt(“age”) ) |
<select id="selectMultiPosition" resultType="com.bjpowernode.domain.Student">
select id,name, email,age from student
</select>
对等的jdbc
ResultSet rs = executeQuery(" select id,name, email,age from student" )
while(rs.next()){
Student student = new Student();
student.setId(rs.getInt("id"));
student.setName(rs.getString("name"))
}
C. map类型:SQL语句返回值是map类型。当sql 的查询结果作为 Map 的 key 和 value时,推荐使用 Map<String,Object>。
注意:Map 作为接口返回值,sql 语句的查询结果最多只能有一条记录。大于一条记录是错误。
返回map用的比较少,一般是返回对象比较多。
3.3.2 定义自定义类型的别名
定义自定义类型的别名
- 在mybatis主配置文件中定义,使<typeAlias>定义别名
- 可以在resultType中使用自定义别名
mybatis主配置文件:
第一种方式:
第二种方式:
一般第二种方式是常用的别名定义。但是还是比较推荐使用全限定名称,比较安全。因为有可能指定包下,有可能会出现同名的类,使用别名的话,就难以区分是哪一个。
mapper文件:
测试类:
运行测试类的结果还是一样:
3.3.3 resultMap
resultMap:结果映射, 指定列名和java对象的属性对应关系。原来是将列名直接赋值给java对象的同名属性,要是你不想将类名赋值给同名属性的话就可以使用returnMap。能更灵活的把列值赋值给指定属性。
使用方式:
- 先定义 resultMap,指定列名和属性的对应关系。
- 在<select>中把 resultType 替换为 resultMap。
使用场景:
- 你自定义列值赋值给哪个属性
- 当你的列名和属性名不一样时,一定使用resultMap
第一种场景:定义列值赋值给哪个属性
从结果中可看到,已经将name列的值复制给了Java对象中的email属性。
第二种场景:列名和属性名不一样
第一种方式是使用returnMap,第二种方式使用returnType,要注意区分。
注意:
- resultMap和resultType不要一起用,二选一
- returnMap的映射关系是可以复用的,只要在其他查询中使用returnMap指定映射关系中定义的id名,就可以直接复用。
3.3.4 模糊 like 的两种方法
模糊查询的实现有两种方式, 一是 java 代码中给查询数据加上“%” ; 二是在 mapper 文件 sql 语句的条件位置加上“%”
第一种方式:java代码中指定like要匹配的内容
第二种方式:在 mapper 文件 sql 语句的条件位置加上“%”
四、动态sql
动态sql: sql的内容是变化的,可以根据条件获取到不同的sql语句。主要是where部分发生变化。主要用于解决查询条件不确定的情况:在程序运行期间,根据用户提交的查询条件进行查询。
动态sql的实现,使用的是mybatis提供的标签,例如<if> ,<where>,<foreach>,来对条件作出判断以实现动态拼接 SQL 语句。
4.1 if标签
<if>是判断条件的,当 test 的值为 true 时,会将其包含的 SQL 片断拼接到其所在的 SQL 语句中。
语法:
<if test=“判断java对象的属性值”>
部分sql语句
</if>
4.2 where标签
<where> 用来包含 多个<if>的, 当多个if有一个成立的, <where>会自动增加一个where关键字, 并去掉 if中多余的 and ,or等。
<if/>标签的不足就是需要在 where 后手工添加 1=1 的子句。因为,若 where 后的所有<if/>条件均为 false,而 where 后若又没有 1=1 子句,则 SQL 中就会只剩下一个空的 where,此时SQL会出错。所以,在 where 后,添加永为真的子句 1=1,以防止这种情况的发生。但当数据量很大时,会
严重影响查询效率。
使用<where/>标签的好处:
在有查询条件时,可以自动添加上 where 子句;没有查询条件时,不会添加where 子句。需要注意的是,第一个<if/>标签中的 SQL 片断,可以不包含 and。不过,写上 and 也可以,系统会将多余的 and 去掉。但其它<if/>中 SQL 片断的 and必须写上,否则 SQL 语句将拼接出错。
4.3 forEach标签
<foreach> 循环java中的数组,list集合的。 主要用在sql的in语句中。
学生id是 1001,1002,1003的三个学生
select * from student where id in (1001,1002,1003)
public List<Student> selectFor(List<Integer> idlist)
List<Integer> list = new ...
list.add(1001);
list.add(1002);
list.add(1003);
dao.selectFor(list)
语法:
<foreach collection="接口中方法参数的类型" item="数组或集合成员的变量" open="开始的字符" close="结束的字符" separator="成员之间的分隔符">
#{xxx}
</foreach>
注意:
collection:表示接口中的方法参数的类型, 如果是数组使用array , 如果是list集合使用list
item:自定义的,表示数组或集合成员的变量
open:循环开始是的字符
close:循环结束时的字符
separator:集合成员之间的分隔符
第一种使用方式:遍历 List<简单类型>,可以用<if>标签来判断list是否为空(list !=null and list.size > 0 ),来动态添加where子句。
第二种方式:遍历 List< 对象类型>
4.4 动态SQL代码段
sql代码片段:就是复用一些SQL语句,通过<sql/>标签定义 SQL 片断,以便其它 SQL 标签复用该代码段。而其它标签使用该 SQL 片断时,需要使用<include/>子标签。该<sql/>标签可以定义 SQL 语句中的任何部分,因此<include/>子标签可以放在动态 SQL的任何位置。
使用步骤:
- 先定义 <sql id=“自定义名称(唯一)”> sql语句, 表名,字段等
- 再使用<include refid=“id的值” />
五、MyBatis 配置文件
5.1 主配置文件
前面的项目中使用的 mybatis.xml 就是主配置文件。
主配置文件特点:
1) 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">
2)根元素<configuration>
3)主要包含内容:
- 定义别名
- 数据源
- mapper 文件
5.2 dataSource 标签
Mybatis 中访问数据库,可以使用连接池技术,但它采用的是自己的连接池技术。在 Mybatis 的 mybatis.xml配置文件中,通过来实现 Mybatis 中连接池的配置。
5.2.1 dataSource 类型
Mybatis 将数据源分为三类:
- UNPOOLED 不使用连接池的数据源
- POOLED 使用连接池的数据源
- JNDI 使用 JNDI 实现的数据源
我们在DataSource上Ctrl+H,可以看到DataSource的实现类有上图中的三个。其中 UNPOOLED ,POOLED 数据源实现了 javax.sq.DataSource 接口, JNDI 和前面两个实现方式不同,了解即可。
5.2.2 dataSource 配置
在 MyBatis.xml 主配置文件,配置 dataSource:
MyBatis 在初始化时,根据<dataSource>的 type 属性来创建相应类型的的数据源 DataSource,即:
type=”POOLED”:MyBatis 会创建 PooledDataSource 实例
type=”UNPOOLED” : MyBatis 会创建 UnpooledDataSource 实例
type=”JNDI”:MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用
5.3 事务
5.3.1 默认需要手动提交事务
Mybatis 框架是对 JDBC 的封装,所以 Mybatis 框架的事务控制方式,本身也是用 JDBC 的事务管理机制,即通过 Connection 的 commit()方法提交,通过 rollback()方法回滚。但默认情况下,MyBatis 将自动提交功能关闭了,改为了手动提交。即程序中需要显式的对事务进行提交或回滚。另外,Connection 对象是通过 setAutoCommit()方法来设置事务提交方式的,分为自动提交和手工提交。
<transactionManager type=“JDBC”/>该标签用于指定MyBatis所使用的事务管理器。MyBatis支持两种事务管理器类型:JDBC 与MANAGED。
5.3.2 自动提交事务
设置自动提交的方式,factory 的 openSession() 分为有参数和无参数的。有参数为 true,使用自动提交,可以修改 MyBatisUtil 的 getSqlSession()方法中的session = factory.openSession(true)语句,再执行sql操作(主要是insert,update,delete操作)时,就无需执行 session.commit()进行事务提交了,此时是自动提交。
5.4 使用数据库属性配置文件
1.数据库的属性配置文件: 把数据库连接信息放到一个单独的文件中。 和mybatis主配置文件分开。目的是便于修改,保存,处理多个数据库的信息。
1)在resources目录中定义一个属性配置文件, xxxx.properties ,例如 jdbc.properties
在属性配置文件中, 定义数据,格式是 key=value
key: 一般使用 . 做多级目录的。
例如 jdbc.mysql.driver , jdbc.driver, mydriver
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql//…
jdbc.username=root
jdbc.password=123456
2)在mybatis的主配置文件,使用<property> 指定文件的位置,并在需要使用值的地方, 通过${key}来指定相关的信息。
5.5 mappers (映射器)
mapper文件是用来定义SQL语句的,通过在mybatis主配置文件中引入mapper文件,相当于这些SQL操作都由mybatis来管理,在业务代码中我们直接调用指定的方法名就可以自动创建SQL语句,传值,执行SQL,并把结果封装成对应的java类型再返回。开发人员只需关注SQL语句的编写,再在业务代码中调用即可,无需关注SQL语句的定义,传值等操作。
定义mapper文件的映射关系,有两种方法:
1.<mapper resource=" " />
使用相对于类路径的资源,从 classpath 路径查找文件
例如:<mapper resource=“com/bjpowernode/dao/StudentDao.xml” />
该方式引入mapper文件有个缺点,就是一个mapper标签对应一个文件,文件多的时候需要一个个的引入,而且还要写出完整的路径,如果写错的话,调用就会失败。
2.mapper文件,使用package指定路径
<mappers>
<!--第二种方式: 使用包名
name: xml文件(mapper文件)所在的包名, 这个包中所有xml文件一次都能加载给mybatis
使用package的要求:
1. mapper文件名称需要和接口名称一样, 区分大小写
2. mapper文件和dao接口需要在同一目录
-->
<package name="com.xzz.dao"/>
</mappers>
六、PageHelper
PageHelper是做数据分页的。
6.1 Mybatis 通用分页插件
PageHelper是Mybatis 通用的分页插件,要使用PageHelper进行页面分页,需要先到https://github.com/pagehelper/Mybatis-PageHelper下载jar包。(如果使用maven添加依赖的话,无需自己下载)
PageHelper 支持多种数据库:
- Oracle
- Mysql
- MariaDB
- SQLite
- Hsqldb
- PostgreSQL
- DB2
- SqlServer(2005,2008)
- Informix
- H2
- SqlServer2012
- Derby
- Phoenix
6.2 基于 PageHelper 分页的实现步骤
1.在pom.xml文件中引入依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>
2.加入 plugin 配置
//在<environments> 之前加入
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor" />
</plugins>
该插件就相当于过滤器。
3.PageHelper 对象
查询语句之前调用 PageHelper.startPage 静态方法。除了 PageHelper.startPage 方法外,还提供了类似用法的 PageHelper.offsetPage 方法。在你需要进行分页的 MyBatis 查询方法前调用 PageHelper.startPage 静态方法即可,紧跟在这个方法后的第一个 MyBatis 查询方法会被进行分页处理。