全网最全、最新MyBatis框架核心知识,这篇文章包你这辈子也忘不掉MyBatis(二)!!

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录。

✨✨MyBatis框架


10.封装MyBatis输出结果


  • MyBatis执行完sql,怎么将sql语句的执行结果变成一个java对象。


10.1 定义自定义类型的别名(比如对象)


  1. mybatis主配置文件中定义,使定义别名
  2. 可以在resultType中使用自定义别名。
<typeAliases>
    <!--
        定义别名的第一种方式
        可以指定一个类型一个自定义别名
        type : 自定义类型的全局限定名称
        alias :别名 (短小、容易记忆的)
    -->
    <!--可以在这里边同时定义多个别名也就是 typeAlias-->
    <typeAlias type="com.yunbocheng.entity.Student" alias="stu"/>
    <!--
        定义别名的第二种方式
        <package> name是包名,这个包中的所有类,类名就是别名(类名不区分大小写)
    -->
    <package name="com.yunbocheng.entity"/>
</typeAliases>
复制代码
  • 不建议使用别名,建议使用全限定名称。全限定名称更安全。因为如果使用通过定义包名的方式定义别名,可能在两个包中都存在Student类,此时返回值使用Student,那不此时不能确定是哪个包中的Student别名。使用的时候会报错,发生奇异。不能确定的到底是使用的哪个包中的Student别名。


10.2 resultType


  • resultType : (结果类型)执行 sql 得到 ResultSet 转换的类型,使用类型的完全限定名别名。
  • 别名是 mybatis 给出的,比如 :全限定名称 java.lang.Interger对应的别名是 INTEGER。
  • 如果*resultType返回值是一个对象,*比如返回值是一个Student对象,此时的resultType返回值可以使用全限定名称。com.yunbocheng.entity.Student。 也可以使用别名。别名定义方式在上边。
  • 注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。
  • resultType 和 resultMap,不能同时使用。
  • resultType结果类型, 指sql语句执行完毕后, 数据转为的java对象, java类型是任意的。

resultType处理方式:

  1. mybatis执行sql语句, 然后mybatis调用类的无参数构造方法,创建对象。
  2. mybatis把ResultSet指定列值付给同名的属性。
<!--mapper文件中的语句,Mybatis动态代理-->
<select id="selectMultiPosition" resultType="com.bjpowernode.domain.Student">
  select id,name, email,age from student
</select>
<!--以上MyBatis动态代理对等的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"));
    student.setEmail(rs.getString("email"));
    student.setAge(rs.getInt("age"));
}
复制代码


10.2.1 resultType返回一个简单类型


第一步 :定义接口中的方法

int countStudent();
复制代码

第二步 :mapper 文件:

注意:返回值类型可以是全限定名称也可以是别名。

<!--此时 resultType 的返回值是一个int类型,代表查询到的结果数-->
<select id="countStudent" resultType="int">
 select count(*) from student
</select>
复制代码

第三步 :测试方法

@Test
public void testRetunInt(){
 int count = studentDao.countStudent();
 System.out.println("学生总人数:"+ count);
}
复制代码


10.2.2 resultType返回一个对象类型(推荐使用)


第一步 :接口中的抽象方法

Student selectById(int id);
复制代码

第二步 :mapper文件

<!--此时返回的结果是一个Student对象-->
<select id="selectById" resultType="com.bjpowernode.domain.Student">
     select id,name,email,age from student where id=#{studentId}
</select>
复制代码

这个是时候会使用框架处理 :使用构造方法创建对象。调用 setXXX 给属性赋值。

微信截图_20220608222714.png

  • 注意:Dao 接口方法返回是集合类型,需要指定集合中的类型,不是集合本身。

微信截图_20220608222724.png

  • 这个java对象可以是任意的,此时就将这个查询结果赋给一个ViewStudendnt对象。

微信截图_20220608222739.png

第三步 :测试程序

@Test
public void testSelectStudent(){
StudentDao studentDao = new StudentDaoImpl();
List<Student> students = studentDao.testSelect();
    for (Student student : students) {
        System.out.println(student);
    }
}
复制代码


10.2.3 resultType返回一个Map类型


  • sql 的查询结果作为 Map 的 key 和 value。推荐使用 Map
  • 注意:Map 作为接口返回值,sql 语句的查询结果最多只能有一条记录。大于一条记录是错误。

第一步 :接口定义抽象方法返回Map

Map<Object,Object> selectReturnMap(int id);
复制代码

第二步 :mapper文件 (返回值map的全限定名称是 java.util.HashMap或者是别名map)

<!--此时返回值是一个Map集合,且这个集合中只能有一条记录。推荐使用Map<Object,Object>-->
<select id="selectReturnMap" resultType="java.util.HashMap">
    select id,name from student where id = #{studentId}
</select>
复制代码

第三步 :测试方法(返回的结果是:列名是map的key,列值是map的value)。

@Test
public void testReturnMap(){
    Map<Object,Object> retMap = studentDao.selectReturnMap(1002);
    System.out.println("查询结果是 Map:"+retMap);
}
复制代码

注意 :上边SQL语句获取的是id,name的字段值。所以传递到Map集合中的是。

返回的结果是 :查询的结果是 Map : {name=李四, id=1001} 查询的结果是:{列名=列值,列名=列值}的格式

以上查询到的是两个key,如果是多个key,其map就是多增加列名和列值。


注意 :使用map只能返回一行数据,返回大一一行的数据会报错,是错误的。


10.3 resultMap


  • resultMap : 结果映射, 指定数据库中数据的列名java对象的属性对应关系。
  • resultMap的作用 :
  1. 你自定义列值赋值给哪个属性。
  2. 当你的列名和属性名不一样时,一定使用resultMap。
  • 这个返回值类型主要解决列名和属性名不一样的问题。

第一步 :创建一个接口的抽象方法

/**
* 使用resultMap定义映射关系
*/
List<Student> selectAllStudents();
复制代码

第二步 :mapper文件

<!--使用resultMap
    1. 先定义一个resultMap
    2. 在select标签中,使用resultMap来调用已定义的resultMap。
-->
<!--定义resultMap
    id : 自定义名称,表示定义的这个resultMap
    type : java类型的全限定名称。相当于以前select的resultType。
-->
<resultMap id="studentMap" type="com.yunbocheng.entity.Student">
    <!--数据库中的列名和java属性的关系-->
    <!--主键列,使用id标签
        column : 数据库中的列名
        property : java类型的属性名
    -->
    <id column="id" property="id"/>
    <!--非主键列,使用result标签-->
    <result column="name" property="name"/>
    <result column="email" property="email"/>
    <result column="age" property="age"/>
</resultMap>
<!--此时这个 resultMap的值就是这个id值studentMap-->
<select id="selectAllStudents" resultMap="studentMap">
    select id,name,email,age from student;
</select>
复制代码

第三步 :测试类 (返回值是一个List集合)

@Test
public void testSelectAllStudents(){
    // 使用工具类获取到SqlSession对象
    SqlSession sqlSession = MyBatisUtils.getSqlSession();
    // 使用mybatis动态代理模式获取到dao的实现类对象
    StudentDao dao = sqlSession.getMapper(StudentDao.class);
    // 使用dao的是实现类对象来调用其中的抽象方法。
    List<Student> students = dao.selectAllStudents();
    for (Student student : students) {
        System.out.println(student);
    }
}
复制代码

注意 :resultMap和resultType不要一起用,二选一。


11.解决实体类属性名与列名不同的处理方式


11.1 使用列别名和 resultType(第一种方式)


使用方式

  • 第一步 :创建新的实体类
package com.yunbocheng.entity;
public class PrimaryStudent {
 private Integer stuId;
 private String stuName;
 private Integer stuAge;
 // 省略了 set , get 以及toString方法
复制代码
  • 第二步 :接口方法 (返回一个不是Student对象的LIst集合)
List<PrimaryStudent> selectUseFieldAlias(QueryParam param);
复制代码
  • 第三步 :mapper文件
<select id="selectUseFieldAlias" 
resultType="com.yunbocheng.entity.PrimaryStudent">
    select id as stuId, name as stuName,age as stuAge
    from student where name=#{queryName} or age=#{queryAge}
</select>
复制代码
  • 测试方法
@Test
public void testSelectUseFieldAlias(){
 QueryParam param = new QueryParam();
 param.setQueryName("程云博");
 param.setQueryAge(20);
 List<PrimaryStudent> stuList;
 stuList = studentDao.selectUseFieldAlias(param);
 stuList.forEach( stu -> System.out.println(stu));
}
复制代码


11.2 使用 resultMap


使用方式

  • 接口方法
List<PrimaryStudent> selectUseDiffResultMap(QueryParam param);
复制代码
  • mapper文件 (使用定义别名的方式)
<!-- 创建 resultMap
 id:自定义的唯一名称,在<select>使用
 type:期望转为的 java 对象的全限定名称或别名 
-->
<resultMap id="primaryStudentMap" 
type="com.yunbocheng.entity.PrimaryStudent">
 <!-- 主键字段使用 id -->
 <id column="id" property="stuId" />
 <!--非主键字段使用 result-->
 <result column="name" property="stuName"/>
 <result column="age" property="stuAge" />
</resultMap>
<!--resultMap: resultMap 标签中的 id 属性值-->
<select id="selectUseDiffResultMap" resultMap="primaryStudentMap">
 select id,name,email,age from student
 where name=#{queryName} or age=#{queryAge}
</select>
复制代码
  • 测试方法
@Test
public void testSelectUseDiffResultMap(){
 QueryParam param = new QueryParam();
 param.setQueryName("程云博");
 param.setQueryAge(20);
 List<PrimaryStudent> stuList;
 stuList = studentDao.selectUseDiffResultMap(param);
 stuList.forEach( stu -> System.out.println(stu));
}
复制代码


12. 模糊查询like


12.1 模糊查询的第一种方式 (推荐使用)


  • 第一种方式 :在Java代码指定 like 的内容。

实现方式

  • 第一步 :接口中创建方法 (返回值是一个Student对象的List集合)传递的参数是模糊的名字
/**
* 第一种模糊查询
* 在Java代码指定 like 的内容。
*/
public List<Student> selectLikeOne(String name);
复制代码
  • 第二步 :mapper文件中创建SQL查询语句 (这里使用 #{} 占位符格式)
<!--第一种like,java代码指定 like内容-->
<select id="selectLikeOne" resultType="com.yunbocheng.entity.Student">
    select id,name,email,age from student where name like #{name};
</select>
复制代码
  • 第三步 :测试方法,使用模糊查询查询结果,此时使用的是模糊查询语句 "%程%",%代表前边有任意个字符,即使没有字符也可以的,只要名字里边有这个字符即可查询出来。
@Test
public void selectSelectLikeOne(){
    SqlSession sqlSession = MyBatisUtils.getSqlSession();
    StudentDao dao = sqlSession.getMapper(StudentDao.class);
    // 准备好like的内容,使用dao接口的实现类对象调用方法
    String name = "%程%";
    List<Student> students = dao.selectLikeOne(name);
    for (Student student : students) {
        System.out.println("查询到的学生 :" + student);
    }
}
复制代码

查询到的结果 :

微信截图_20220608225730.png

12.2 模糊查询的第一种方式



  • 在mapper文件中拼接 like 的内容

实现方式

  • 接口方法
/**
 * 第二种模糊like查询的方法
 * name就是 程 这个值,在mapper文件中拼接 like %程% 
 */
List<Student> selectLikeTwo(String name);
复制代码
  • mapper文件
<!--第二种方式 :在mapper文件中拼接like内容 %程%-->
<!--如果要求查询的第一个字符是程,那么就不写第一个 "%"-->
<!--注意 :这个"%"与#{name}之间的空格必须存在-->
<!--这个name为查询的值,比如 程,这样拼接之后就是 %程%-->
<select id="selectLikeOne" resultType="com.yunbocheng.entity.Student">
    select id,name,email,age from student where name like "%" #{name} "%";
</select>
复制代码
  • 测试方法
@Test
public void selectSelectLikeTwo(){
    SqlSession sqlSession = MyBatisUtils1.getSqlSession();
    StudentDao dao = sqlSession.getMapper(StudentDao.class);
    // 准备好like的内容,使用dao接口的实现类对象调用方法
    String name = "李";
    List<Student> students = dao.selectLikeOne(name);
    for (Student student : students) {
        System.out.println("查询到的学生 :" + student);
    }
}
复制代码
  • 测试结果

微信截图_20220608230253.png

13.动态sql概念


  • 动态sql : sql的内容是变化的,可以根据条件获取到不同的sql语句。
  • 主要是where部分发生变化。
  • 动态sql的实现,使用的是mybatis提供的标签:
  • if 标签
  • where 标签
  • foreach 标签
  • 动态 SQL,通过 MyBatis 提供的各种标签对条件作出判断以实现动态拼接 SQL 语句。这里的条件判 断使用的表达式为 OGNL 表达式。常用的动态 SQL 标签有、、、等。 MyBatis 的动态 SQL 语句,与 JSTL 中的语句非常相似。 动态 SQL,主要用于解决查询条件不确定的情况:在程序运行期间,根据用户提交的查询条件进行 查询。提交的查询条件不同,执行的 SQL 语句不同。若将每种可能的情况均逐一列出,对所有条件进行 排列组合,将会出现大量的 SQL 语句。此时,可使用动态 SQL 来解决这样的问题
  • 在 mapper 的动态 SQL 中若出现大于号(>)、小于号(<)、大于等于号(>=),小于等于号(<=)等 符号,最好将其转换为实体符号。否则,XML 可能会出现解析出错问题。
  • 特别是对于小于号(<),在 XML 中是绝不能出现的。否则解析 mapper 文件会出错。


13.1 if 标签


  • if 是判断条件的。
  • if中存在一个问题,就是可能发生SQL语句拼接错误。Where标签会解决这个问题。
  • 语法格式:
<if test="判断java对象的属性值">
    部分sql语句
</if>
复制代码

对于该标签的执行,当 test 的值为 true 时,会将其包含的 SQL 片断拼接到其所在的 SQL 语句中。 语法: sql 语句的部分

实现方式

  • 第一步 :创建接口中的抽象方法(注意 : sql动态代理动态sql要使用java对象作为参数
/*
    测试动态sql中的 if 标签
    动态sql要使用java对象作为参数
*/
List<Student> selectStudentIf(Student student);
复制代码
  • 第二步 :在mapper文件中使用动态sql语句。
  • 下边代码中存在一个小技巧id > 0,这个代码的作用是为了:使当输入的name不满足条件时可以拼接出正确SQL语句。因为表中的所有id都是大于0的 ,不影响查询结果。这个小技巧不一定非得是id>0,只要是true的表达式即可。比如:1=1 都可以的。
  • 当name不满足条件时,不使用id>0,拼接的字符串是 :
select id,name,email,age from student where and age > ?; //不符合SQL语句格式,会报错。
复制代码
  • 当name不满足条件时,使用id>0,拼接的字符串是 :
select id,name,email,age from student where id>0 and age > ?; 
//因为表中的所有id都是大于0的 ,不影响查询结果,此时符合SQL语句格式。
复制代码
<!--if标签
    <if : test="使用接口中参数Java对象的属性值作为i判断条件">
    语法格式 :属性=xxx值 (当然也可以是 属性!=xxx值)
-->
<select id="selectStudentIf" resultType="com.yunbocheng.entity.Student">
    select id,name,email,age from student
    where id > 0
    <if test="name != null and name != '' ">
        name = #{name} 
    </if>
    <if test="age > 0">
        and age > #{age};
    </if>
</select>
复制代码

以上语句拼接出的SQL语句是:

select id,name,email,age from student where name = ? and age > ?; //?占位符 
复制代码
  • 第三步 :测试方法
// 测试if标签
@Test
public void testSelectStudentIf(){
    SqlSession sqlSession = MyBatisUtils1.getSqlSession();
    StudentDao dao = sqlSession.getMapper(StudentDao.class);
    Student student = new Student();
    student.setName("");
    student.setAge(10);
    List<Student> students = dao.selectStudentIf(student);
    for (Student student1 : students) {
        System.out.println("if===" + student1);
    }
}
复制代码
  • 输出的结果是:

微信截图_20220608230451.png

13.2 where 标签


  • where标签 : where标签是用来包含多个if的
  • where的作用:当多个if有一个成立的,where会自动增加一个where关键字体。并且去掉多余的拼接属性字符,比如 :and or 等。

实现方式:

  • 第一步 :创建接口中的抽象方法(注意 : sql动态代理动态sql要使用java对象作为参数
/**
 * 测试动态sql中的 where 标签
 * 动态sql要使用java对象作为参数
 */
List<Student> selectStudentWhere(Student student);
复制代码
  • 第二步 :在mapper文件中使用动态sql语句。
  • 使用where标签会自动帮我们添加where关键字并且消除多余的or、and语句。如下语句:

微信截图_20220608230552.png

即使我们传递的名字是一个空的,这个时候也会拼接出正确的SQL,不会报错

<select id="selectStudentWhere" resultType="com.yunbocheng.entity.Student">
    select id,name,email,age from student
    <where>
        <if test="name != null and name != '' ">
            name = #{name}
        </if>
        <if test="age > 0">
        and age > #{age};
        </if>
    </where>
</select>
复制代码
  • 第三步 :测试方法
// 测试where标签
@Test
public void testSelectStudentWhere() {
    SqlSession sqlSession = MyBatis.getSqlSession();
    StudentDao dao = sqlSession.getMapper(StudentDao.class);
    Student student = new Student();
    student.setName("");
    student.setAge(100);
    List<Student> students = dao.selectStudentWhere(student);
    for (Student student1 : students) {
        System.out.println(student1);
    }
}
复制代码


13.3 foreach 语句


  • foreach : 循环java中的数组,list集合的。 主要用在sql的in语句中。 比如:查询id是 1001,1002,1003的三个学生。
select * from student where id in (1001,1002,1003);
复制代码
  • 标签用于实现对于数组集合的遍历
  • collection 表示要遍历的集合类型, list ,array 等。
  • open、close、separator 为对遍历内容的 SQL 拼接。
  • 语法格式:
<foreach collection="集合类型" open="开始的字符" close="结束的字符" 
item="集合中的成员" separator="集合成员之间的分隔符">
    #{item 的值}
</foreach>
复制代码

参数解释:

  • collection :表示接口中的方法参数的类型, 如果是数组使用array , 如果是list集合使用list。
  • item: 自定义的,表示数组和集合成员的变量
  • open :循环开始是的字符
  • close :循环结束时的字符
  • separator :集合成员之间的分隔符


13.3.1 遍历 List<简单类型>


  • 表达式中的 List 使用 list 表示,其大小使用 list.size 表示。

实现方式需求:查询学生 id 是 1002,1005,1006

  • 第一步 :接口中定义抽象方法 参数是一个简单的Integer类型集合类型
List<Student> selectStudentForeach(List<Integer> stulist);
复制代码
  • 第二步 :mapper文件
<!--
    测试foreach标签 此时遍历的是一个简单类型
-->
<select id="selectStudentForeach" resultType="com.yunbocheng.entity.Student">
    <!--此时item的值是一个属性,直接使用即可-->
    select id,name,email,age from student where id in
    <foreach collection="list" item="myid" open="(" close=")" separator=",">
        #{myid}
    </foreach>
</select>
<!--注意:这个collection中的liet与测试方法中的list没有关系。-->
复制代码
  • 第三步 :测试方法
// 测试foreach
@Test
public void testSelectForEachOne() {
    SqlSession sqlSession = MyBatis.getSqlSession();
    StudentDao dao = sqlSession.getMapper(StudentDao.class);
    List<Integer> list = new ArrayList<>();
    list.add(1002);
    list.add(1003);
    list.add(1004);
    List<Student> students = dao.selectStudentForeach(list);
    for (Student student1 : students) {
        System.out.println(student1);
    }
}
复制代码
  • 拼接的查询语句:使用foreach会自动拼接出这个in格式的SQL语句
  • 此时查询出的是一个id=1002,id=1003,id=1004 的所有学生。

微信截图_20220608231208.png

  • 输出的结果:

微信截图_20220608231224.png

13.3.2 遍历 List<对象类型>


  • 使用对象可以一次性向SQL语句中传递多个参数值。
  • 自己创建两个对象,创建出一个对象集合,进行实现。
  • 第一步:接口中的抽象方法 参数是一个简单的对象集合类型
List<Student> selectStudentForeachTwo(List<Student> stuList);
复制代码
  • 第二步 :mapper文件
<!--
    测试foreach遍历对象集合
-->
<select id="selectStudentForeachTwo" resultType="com.yunbocheng.entity.Student">
    select id,name,email,age from student where id in
    <!--此时stu是一个Student对象集合 这个stu与测试方法中的studentList没有关系-->
    <foreach collection="list" item="stu" open="(" close=")" separator=",">
        <!--这个语法格式是 :对象.属性值 获取的是id属性的值,如果是 #{stu.name}此时获取的name属性-->
        #{stu.id}
    </foreach>
</select>
复制代码
  • 第三步 :测试方法
// 测试foreach遍历对对象集合
@Test
public void testSelectForEachTwo() {
    SqlSession sqlSession = MyBatis.getSqlSession();
    StudentDao dao = sqlSession.getMapper(StudentDao.class);
    //定义一个Student对象集合
    List<Student> studentList = new ArrayList<>();
    // 创建第一个Student对象
    Student student1 = new Student();
    // 给id属性赋值
    student1.setId(1002);
    // 将这个对象加入到Student对象集合中
    studentList.add(student1);
    // 创建第二个Student对象
    Student student2 = new Student();
    student2.setId(1003);
    studentList.add(student2);
    // 此时对象集合中有两个对象(student1 student2)
    List<Student> studentList1 = dao.selectStudentForeachTwo(studentList);
    for (Student student : studentList1) {
        System.out.println(student);
    }
}
复制代码
  • 拼接的SQL语句此时查询的是id=1002,id=1003的学生

微信截图_20220608231507.png

  • 输出的结果:

微信截图_20220608231518.png

13.3.3 foreach很灵活


  • 修改mapper文件,我们可以不使用 open以及close属性,我们自己拼接这个SQL语句。就是这个语句。我们不使用open="("  和  close=")",而是自己拼接这个开始和结束字符。
<select id="selectStudentForeachTwo" resultType="com.yunbocheng.entity.Student">
    select id,name,email,age from student where id in (
    <!--此时stu是一个Student对象集合 这个stu与测试方法中的studentList没有关系-->
    <foreach collection="list" item="stu" separator=",">
        <!--这个语法格式是 :对象.属性值 获取的是id属性的值,如果是 #{stu.name}此时获取的name属性-->
        #{stu.id}
    </foreach>
    )
</select>
复制代码
  • 使用以上我们手动拼接的SQL语句与使用open和colse属性拼接出的SQL语句是一样的。


13.4 动态sql-代码片段


  • sql标签用于定义 SQL 片断,以便其它 SQL 标签复用。而其它标签使用该 SQL 片断,需要使用 子标签。该标签可以定义 SQL 语句中的任何部分,所以子标签可以放在动态 SQL 的任何位置。
  • sql代码片段,就是复用一些语法,我们在实际的开发过程中,难免会书写重复的SQL语句,这个重复的SQL语句可能是一整条SQL语句,也可能是SQL语句的一部分,我们这个时候可以使用动态sql-代码片段的方式将这个些重复的SQL语句包装起来,定义一个id属性,便于我们以后使用。
  • 在一个mapper文件中可以定义多个代码片段

使用方式

  1. 先在mapper文件中定义  sql语句, 表名,字段等
  2. 再使用,

实现方式

  • 定义接口中的抽象方法,
<!--这个定义一个 if标签 方法-->
List<Student> selectStudentIf(Student student);
<!--这个定义一个 where标签 方法-->
List<Student> selectStudentWhere(Student student);    
复制代码
  • 修改mapper文件,以下两个SQL语句中都需要select id,name,email,age from student。这个语句,我们此时将这个语句放在动态sql-代码片段中,定义一个别名,可以让我们重复使用。
<!--定义sql片段,给以下这段代码定义为动态片段,定义一个别名,以后代码可以重复利用-->
<sql id="studentSql">
</sql>
<!--以下代码是使用 if标签 查询数据的SQL语句-->
<select id="selectStudentIf" resultType="com.yunbocheng.entity.Student">
    <include refid="studentSql"/>
    where id>0 and
    <if test="name != null and name != '' ">
        name = #{name}
    </if>
    <if test="age > 0">
     and  age > #{age};
    </if>
</select>
<!--以下代码是使用 where标签 查询数据的SQL语句-->
<select id="selectStudentWhere" resultType="com.yunbocheng.entity.Student">
    <include refid="studentSql"/>
    <where>
        <if test="name != null and name != '' ">
            name = #{name}
        </if>
        <if test="age > 0">
        and age > #{age};
        </if>
    </where>
</select>
复制代码
  • 测试方法,以下我们只测试一个,测试结果和以前一样不。
// 测试sql-代码片段
@Test
public void testSelectStudentIf() {
    SqlSession sqlSession = MyBatis.getSqlSession();
    StudentDao dao = sqlSession.getMapper(StudentDao.class);
    Student student = new Student();
    student.setName("程云博");
    student.setAge(10);
    List<Student> students = dao.selectStudentIf(student);
    for (Student student1 : students) {
        System.out.println("if===" + student1);
    }
}
复制代码
  • 查询结果,我们可以看到查询结果是和不使用动态代码的结果是一样的。

微信截图_20220608231629.png

  • 我们还可以定义一段类名或者代码片段
<!--定义一个只包含列名的代码片段-->
<sql id="studentOne">
    id,name,email,age  
</sql>
<!--使用动态代码片段创建SQL语句-->
<select id="selectStudentIf" resultType="com.yunbocheng.entity.Student">
    select <include refid="studentOne"/> from student
    where id>0 and
    <if test="name != null and name != '' ">
        name = #{name}
    </if>
    <if test="age > 0">
     and  age > #{age};
    </if>
</select>
复制代码
  • 这样我们需要自己拼接剩余的SQL。


14.MyBatis配置文件


14.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">
复制代码
  1. 根元素,configuration
  2. 主要包含内容: 定义别名数据源mapper 文件


14.2 dataSource 标签


  • Mybatis 中访问数据库,可以连接池技术,但它采用的是自己的连接池技术。
  • 在 Mybatis 的 mybatis.xml 配置文件中,通过来实现 Mybatis 中连接池的配置。


14.2.1 dataSource 类型

微信截图_20220608231750.png

上图看出 Mybatis 将数据源分为三类:

微信截图_20220608231801.png

其中 UNPOOLED ,POOLED 数据源实现了 javax.sq.DataSource 接口, JNDI 和前面两个实现方式不同,了解可以。

微信截图_20220608231811.png

14.2.2 dataSource 配置


  • 在 MyBatis.xml 主配置文件,配置 dataSource
<dataSource type="POOLED">
 <!--连接数据库的四个要素-->
 <property name="driver" value="com.mysql.jdbc.Driver"/>
 <property name="url" 
value="jdbc:mysql://localhost:3306/ssm?charset=utf-8"/>
 <property name="username" value="root"/>
 <property name="password" value="123456"/>
</dataSource>
复制代码

MyBatis 在初始化时,根据的 type 属性来创建相应类型的的数据源 DataSource

  • type=”POOLED”:MyBatis 会创建 PooledDataSource 实例
  • type=”UNPOOLED” : MyBatis 会创建 UnpooledDataSource 实例
  • type=”JNDI”:MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用


14.3 事务


14.3.1 默认需要手动提交事务


  • Mybatis 框架是对 JDBC 的封装,所以 Mybatis 框架的事务控制方式,本身也是用 JDBC 的 Connection 对象的 commit(), rollback() 。
  • Connection 对象的 setAutoCommit()方法来设置事务提交方式的。自动提交和手工提交
<transactionManager type="JDBC"/>
复制代码
  • 该标签用于指定 MyBatis所使用的事务管理器。MyBatis 支持两种事务管理器类型:JDBC 与 MANAGED。
  • JDBC:使用 JDBC 的事务管理机制。即,通过 Connection 的 commit()方法提交,通过 rollback()方法 回滚。但默认情况下,MyBatis 将自动提交功能关闭了,改为了手动提交。即程序中需要显式的对 事务进行提交或回滚。从日志的输出信息中可以看到。

微信截图_20220608231915.png

  • MANAGED:由容器来管理事务的整个生命周期(如 Spring 容器)。

微信截图_20220608231927.png

14.3.2 自动提交事务


  • 设置自动提交的方式,factory 的 openSession() 分为有参数和无参数的。

微信截图_20220608232013.png

  • 有参数为 true,使用自动提交,可以修改 MyBatisUtil 的 getSqlSession()方法。
session = factory.openSession(true);
复制代码
  • 再执行 insert 操作,无需执行 session.commit(),事务是自动提交的


14.4 数据库属性配置文件


  • 为了方便对数据库连接的管理DB(数据存储单位)连接四要素数据一般都是存放在一个专门的属性文件中的。MyBatis 主配置文件需要从这个属性文件中读取这些数据。
  • 目的是便于修改、保存、处理多个数据库的信息。
  • 这样做的目的是不用修改Mybatis文件,只需要修改properties配置文件即可。
  • 这样可以在一个properties配置文件创建连接多个数据库信息,在主配置文件中想使用哪个数据库直接修改即可。可以更加方便的维护mybatis主配置文件。

使用方式

  1. 在 resources 路径下,创建 properties 文件,在这个创建一个jdbc.properties配置文件
    resources 目录创建 xxxx.properties 属性配置文件,文件名称自定义。
    例如:jdbc.properties
    在属性配置文件中,定义数据,*格式是 :key = value * (其中key和value是自定义的)
    key : 一般使用 ,做多级目录的(一般使用两级到三级的)。 例如 : jdbc.mysql.driver 或者 jdbc.deiver。如果不想这个使用,使用*mydriver * 也完全没有问题。
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql//.....
jdbc.username=root
jdbc.password=123456
复制代码
  1. 在mybatis的主配置文件,使用 指定文件的位置 。 在需要使用值的地方*${key}*
<!--指定properties配置文件所在的位置,从类路径根开始找文件-->
<!--这个类路径的根路径就是这个resources 文件-->
<!--修改主配置文件,文件开始位置加入-->
<configuration>
    <properties resource = "jdbc.properties" />
复制代码
  1. 使用 key 指定值,使用的格式是 :${key}
<!--其中key是 jdbc.properties 配置文件中的key-->
<dataSource type="POOLED">
 <!--使用 properties 文件: 语法 ${key}-->
 <property name="driver" value="${jdbc.driver}"/>
 <property name="url" value="${jdbc.url}"/>
 <property name="username" value="${jdbc.username}"/>
 <property name="password" value="${jdbc.password}"/>
</dataSource>
复制代码


14.5 typeAliases(类型别名)


  • Mybatis 支持默认别名,我们也可以采用自定义别名方式来开发。
  • 主要使用在 : select resultType="别名"
  • 第一步 :mybatis.xml 主配置文件定义别名:
<typeAliases>
 <!--
 定义单个类型的别名
 type:类型的全限定名称
 alias:自定义别名 
 -->
 <typeAlias type="com.yunbocheng.entity.Student" alias="mystudent"/>
<!--
 批量定义别名,扫描整个包下的类,别名为类名(首字母大写或小写都可以)
 name:包名 
 -->
 <package name="com.yunbocheng.entity"/>
 <package name="...其他包"/>
</typeAliases>    
复制代码
  • 第二步 :mapper.xml 文件,使用别名表示类型
<select id="selectStudents" resultType="mystudent">
 select id,name,email,age from student
</select>
复制代码


14.6 mappers(映射器)


14.6.1 第一种方式 (使用mapper文件)mapper resource=" "


  • mapper依一次只能指定一个文件,如果有多个mapper文件,需要创建多个mapper文件。
  • 使用相对于类路径的资源,从 classpath(Java文件)路径查找文件
<!--resource代表这个项目的一个mapper文件地址,这个地址从Java根路径开始-->
<mapper resource="com/yunbocheng/dao/StudentDao.xml" /> 
复制代码


14.6.2 第二种方式(使用包名) package name=""


  • 指定包下的所有 Dao 接口
<!--name: xml文件(mapper文件)所在的包名,可以导入多个包名-->
<!--name:xml文件(mapper文件)所在的包名,这个包中的所有xml文件一次都能加载给mybatis-->
<package name="com.yunbocheng.entity"/>
<package name="com.yunbocheng.entity1"/>
<package name="com.yunbocheng.entity2"/>
复制代码
  • 注意:此种方法要求 Dao 接口名称和 mapper 映射文件名称相同(区分大小写),且在同一个目录中。
相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
SQL Java 数据库连接
MyBatis 优秀的持久层框架(一)
MyBatis 优秀的持久层框架
64 0
|
1月前
|
SQL 关系型数据库 Java
Mybatis-Flex框架初体验
Mybatis-Flex框架初体验
|
2月前
|
SQL Java 数据库连接
|
12天前
|
SQL Java 数据库连接
什么是MyBatis持久层框架?
MyBatis 是一个优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs (Plain Old Java Objects, 普通的 Java 对象) 映射成数据库中的记录。
24 5
|
27天前
|
SQL XML Java
这样使用MyBatis框架,被攻击了
这样使用MyBatis框架,被攻击了
13 0
|
28天前
|
Java fastjson Apache
Spring Boot+Gradle+ MyBatisPlus3.x搭建企业级的后台分离框架
Spring Boot+Gradle+ MyBatisPlus3.x搭建企业级的后台分离框架
30 1
|
1月前
|
XML Java 数据库连接
【MyBatis】 框架原理
【MyBatis】 框架原理
17 0
|
2月前
|
前端开发 Java 数据库连接
认识Java中最常用的框架:Spring、Spring MVC、Spring Boot、MyBatis和Netty
Spring框架 Spring是一个轻量级的开源框架,用于构建企业级应用。它提供了广泛的功能,包括依赖注入、面向切面编程、事务管理、消息传递等。Spring的核心思想是控制反转(IoC)和面向切面编程(AOP)。
77 3
|
2月前
|
SQL Java 关系型数据库
【MyBatis-Plus】快速精通Mybatis-plus框架—核心功能
【MyBatis-Plus】快速精通Mybatis-plus框架—核心功能
48 0
【MyBatis-Plus】快速精通Mybatis-plus框架—核心功能
|
2月前
|
SQL Java 数据库连接
【MyBatis-Plus】快速精通Mybatis-plus框架—快速入门
【MyBatis-Plus】快速精通Mybatis-plus框架—快速入门
49 0