飞道的博客

Mybatis框架(全部基础知识)

459人阅读  评论(0)

👌 棒棒有言:也许我一直照着别人的方向飞,可是这次,我想要用我的方式飞翔一次!人生,既要淡,又要有味。凡事不必太在意,一切随缘,缘深多聚聚,缘浅随它去。凡事看淡点看开些,顺其自然,无意于得,就无所谓失。人生,看轻看淡多少,痛苦就远离你多少。

👌 本章简介:MyBatis本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation迁移到了google code,并且改名为MyBatis。2013年11月迁移到Github。iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAOs)。

当前,最新版本是MyBatis 3.5.11,其发布时间是2022年09月18日。

👍  作者:get棒棒给个关注呗

👍非常重要 :

如果不介意麻烦动动你们的小手点个关注

Mybatis框架

MyBatis简介

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录

2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。

回顾JDBC的使用步骤:

  • 1.加载驱动

Class.forName("com.mysql.jdbc.Driver");
  • 2.获取连接对象

DiverManerger.getConnection(url,username,password)
  • 3.获取执行sql的Statement对象

connection.CreateStatement();
  • 4.执行sql语句

  • 5.处理结果集

  • 6.释放连接

connection.Close()

与JDBC相比:

  1. Mybatis通过参数映射方式,可以将参数灵活的配置在SQL语句中的配置文件中,避免在Java类中配置参数

  2. Mybatis通过输出映射机制,将结果集的检索自动映射成相应的Java对象,避免对结果集手工检索

  3. Mybatis可以通过Xml配置文件对数据库连接进行管理

MyBatis整体架构及运行流程

Mybatis整体构造由 数据源配置文件、Sql映射文件、会话工厂、会话、执行器和底层封装对象组成

1.数据源配置文件

通过配置的方式将数据库的配置信息从应用程序中独立出来,由独立的模块管理和配置。Mybatis的数据源配置文件包含数据库驱动、数据库连接地址、用户名密码、事务管理等,还可以配置连接池的连接数、空闲时间等

一个MapConfig.xml基本的配置信息如下:


  
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration
  3.   PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4.   "http://mybatis.org/dtd/mybatis-3-config.dtd">
  5. <configuration>
  6.   <environments default="development">
  7.     <environment id="development">
  8.   <!-- 事务的管理 JDBC  MANAGED-->
  9.       <transactionManager type="JDBC"/>
  10.   <!-- 数据源 POOLED UNPOOLED JNDI -->
  11.       <dataSource type="POOLED">
  12.         <property name="driver" value="${driver}"/>
  13.         <property name="url" value="${url}"/>
  14.         <property name="username" value="${username}"/>
  15.         <property name="password" value="${password}"/>
  16.       </dataSource>
  17.     </environment>
  18.   </environments>
  19.   <mappers>
  20.     <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  21.   </mappers>
  22. </configuration>

mybatis mapper文件映射

<!-- 使用相对于类路径的资源引用 -->

  
  1. <mappers>
  2.   <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  3. </mappers>
<!-- 使用映射器接口实现类的完全限定类名
    mybais去加载class对应的接口,然后还会去加载该接口同目录下的同名xml文件 
-->

  
  1. <mappers>
  2.   <mapper class="org.mybatis.builder.AuthorMapper"/>
  3. </mappers>
<!-- 将包内的映射器接口实现全部注册为映射器   
 使用package元素批量注册Mapper接口
  1.包名和接口所在的包名字一致
  2.mapper文件的名字和接口的名字一致
  3.创建包是使用/分割
-->

  
  1. <mappers>
  2.   <package name="org.mybatis.builder"/>
  3. </mappers>

设置资源文件路径

Maven中默认是只会打包resource下的资源文件。如果我们的文件不放在resource, 则需要通过配置告知Maven


  
  1. <resources>
  2.     <resource>
  3.         <directory>src/main/java </directory>
  4.         <includes>
  5.             <include>**/*.properties </include>
  6.             <include>**/*.xml </include>
  7.         </includes>
  8.         <filtering>false </filtering>
  9.     </resource>
  10.     <resource>
  11.         <directory>src/main/resources </directory>
  12.         <includes>
  13.           <include>**/*.properties </include>
  14.           <include>**/*.xml </include>
  15.           <include>**/*.tld </include>
  16.         </includes>
  17.         <filtering>false </filtering>
  18.       </resource>
  19. </resources>

2.Sql映射文件

Mybatis中所有数据库的操作都会基于该映射文件和配置的sql语句,在这个配置文件中可以配置任何类型的sql语句。框架会根据配置文件中的参数配置,完成对sql语句以及输入输出参数的映射配置。

Mapper.xml配置文件大致如下:


  
  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
  3. <mapper namespace="命名空间">
  4. <select id="方法名" resultMap="返回值类型" parameterType="参数类型">
  5. -- sql语句
  6. </select>
  7. </mapper>

3.会话工厂与会话

Mybatis中会话工厂SqlSessionFactory类可以通过加载资源文件,读取数据源配置MapConfig.xml信息,从而产生一种可以与数据库交互的会话实例SqlSession,会话实例SqlSession根据Mapper.xml文件中配置的sql,对数据库进行操作。

4.运行流程

会话工厂SqlSessionFactory通过加载资源文件获取MapConfig.xml配置文件信息,然后生成可以与数据库交互的会话实例SqlSession。会话实例可以根据Mapper配置文件中的Sql配置去执行相应的增删改查操作

执行流程图:

mybatis实现增删改查


  
  1. public class TestStudent {
  2.     @Test
  3.     public void test01 (){
  4.         try { //加载配置文件
  5.             InputStream in = Resources.getResourceAsStream( "config/mybatis-config.xml");
  6.             //获取sqlSession对象
  7.             SqlSession sqlSession = new SqlSessionFactoryBuilder().build(in).openSession();
  8.             //查询所有学生信息
  9.        List<Student> students = sqlSession.selectList( "cn.kgc.mybatis.dao.StudentDao.getAll");
  10.            students.forEach(student -> System.out.println(student) );
  11.       } catch (IOException e) {
  12.            e.printStackTrace();
  13.       }
  14.   }
  15.     @Test
  16.     public void test02 (){ //查询一个学生信息
  17.         try { //加载配置文件
  18.             InputStream in = Resources.getResourceAsStream( "config/mybatis-config.xml");
  19.             //获取sqlSession对象
  20.             SqlSession sqlSession = new SqlSessionFactoryBuilder().build(in).openSession();
  21.             //根据用户名查询一个学生信息
  22.             Student student = sqlSession.selectOne( "cn.kgc.mybatis.dao.StudentDao.findOne", "tom");
  23.            System.out.println(student);
  24.            sqlSession.close();
  25.       } catch (IOException e) {
  26.            e.printStackTrace();
  27.       }
  28.   }
  29.     @Test
  30.     public void test03 () { //添加一个学生信息
  31.         try { //加载配置文件
  32.             InputStream in = Resources.getResourceAsStream( "config/mybatis-config.xml");
  33.             //获取sqlSession对象
  34.             SqlSession sqlSession = new SqlSessionFactoryBuilder().build(in).openSession();
  35.             //添加一个学生信息
  36.             Student student = Student.builder().stuBirth( new Date()).stuName( "lilei").stuNo( "2021073001").stuSex( "男").build();
  37.             int i = sqlSession.insert( "cn.kgc.mybatis.dao.StudentDao.addOne", student);
  38.            System.out.println(i);
  39.            sqlSession.commit();
  40.            sqlSession.close();
  41.       } catch (IOException e) {
  42.            e.printStackTrace();
  43.       }
  44.   }
  45.     @Test
  46.     public void test04 () { //删除一个学生信息
  47.         try{
  48.             InputStream in = Resources.getResourceAsStream( "config/mybatis-config.xml");
  49.             //获取sqlSession对象 同时可设置事务的自动提交 openSession(true)
  50.             SqlSession sqlSession = new SqlSessionFactoryBuilder().build(in).openSession();
  51.             int delete = sqlSession.delete( "cn.kgc.mybatis.dao.StudentDao.delOne", "lilei" );
  52.            sqlSession.commit();
  53.            sqlSession.close();
  54.            System.out.println(delete);
  55.       } catch (Exception e){
  56.            e.printStackTrace();
  57.       }
  58.   }
  59.     @Test
  60.     public void test05 () { //修改一个学生信息
  61.         try{
  62.             InputStream in = Resources.getResourceAsStream( "config/mybatis-config.xml");
  63.             //获取sqlSession对象
  64.             SqlSession sqlSession = new SqlSessionFactoryBuilder().build(in).openSession();
  65.             Student student = Student.builder().stuBirth( new Date()).stuName( "lili").stuNo( "2021073001").stuSex( "女").build();
  66.             int delete = sqlSession.update( "cn.kgc.mybatis.dao.StudentDao.updateStudent",student);
  67.            sqlSession.commit();
  68.            sqlSession.close();
  69.            System.out.println(delete);
  70.       } catch (Exception e){
  71.            e.printStackTrace();
  72.       }
  73.   }
  74. }

mybatis中使用log4j日志工具

1.配置mybatis-config.xml


  
  1. <!--    开启日志-->
  2. <setting name="logImpl" value="LOG4J"/>

开启驼峰命名


  
  1. <!--    设置驼峰命名-->
  2. <setting name="mapUnderscoreToCamelCase" value="true"/>

设置别名


  
  1. <typeAliases>
  2.     <!--设置别名-->
  3.     <package name="cn.kgc.mybatis.pojo"/>
  4. </typeAliases>

2.配置log4j.properties文件,放置在resources目录下


  
  1. log4j.rootLogger=DEBUG,Console
  2. #Console
  3. log4j.appender.Console=org.apache.log4j.ConsoleAppender
  4. log4j.appender.console.Target=System.out
  5. log4j.appender.Console.layout=org.apache.log4j.PatternLayout
  6. log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
  7. log4j.logger.org.apache=ERROR
  8. log4j.logger.org.mybatis=ERROR
  9. log4j.logger.org.springframework=ERROR
  10. #这个需要
  11. log4j.logger.log4jdbc.debug=ERROR
  12. log4j.logger.com.gk.mapper=ERROR
  13. log4j.logger.jdbc.audit=ERROR
  14. log4j.logger.jdbc.resultset=ERROR
  15. #这个打印SQL语句非常重要
  16. log4j.logger.jdbc.sqlonly=DEBUG
  17. log4j.logger.jdbc.sqltiming=ERROR
  18. log4j.logger.jdbc.connection=FATAL

使用mapper代理对象实现增删改查


  
  1. public class TestStudentMapper {
  2.    SqlSessionFactory factory;
  3.     @Before
  4.     public void init (){
  5.         try {
  6.             InputStream   in = Resources.getResourceAsStream( "config/mybatis-config.xml");
  7.             SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();
  8.            factory = sfb.build(in);
  9.       } catch (IOException e) {
  10.            e.printStackTrace();
  11.       }
  12.   }
  13.     @Test
  14.     public void test01 (){
  15.             //开启事务自动提交
  16.             SqlSession sqlSession = factory.openSession( true);
  17.             //获取dao层的代理对象
  18.             StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
  19.            List<Student> students = studentDao.getAll();
  20.            students.forEach(student -> System.out.println(student));
  21.   }
  22.     @Test
  23.     public void test02 (){ //添加数据
  24.         SqlSession sqlSession = factory.openSession( true);
  25.         Student student = Student.builder().stuSex( "男").stuNo( "2021073100").stuName( "李四").stuBirth( new Date()).build();
  26.         StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
  27.         Integer line = studentDao.addOne(student);
  28.        System.out.println(line);
  29.   }
  30.     @Test
  31.     public   void test03 (){ //删除一条数据
  32.         SqlSession sqlSession = factory.openSession( true);
  33.         StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
  34.         Integer line = studentDao.delOne( "李四");
  35.        System.out.println(line);
  36.   }
  37.     @Test
  38.     public void test04 () { //修改数据
  39.         SqlSession sqlSession = factory.openSession( true);
  40.         StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
  41.         Student student = Student.builder().stuSex( "女").stuNo( "2021073100").stuName( "李四").stuBirth( new Date()).build();
  42.         Integer line = studentDao.updateOne(student);
  43.        System.out.println(line);
  44.   }
  45.    
  46.     @Test
  47.     public void test06 (){ //模糊查询一个学生信息 一个参数
  48.         SqlSession sqlSession = factory.openSession( true);
  49.         StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
  50.        List<Student> students = studentDao.selectLikeName( "li");
  51.        System.out.println(students.toString());
  52.   }
  53.     @Test
  54.     public void test07 (){ //模糊查询一个学生信息 两个参数
  55.         SqlSession sqlSession = factory.openSession( true);
  56.         StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
  57.        List<Student> students = studentDao.selectLikeName2( "li", "2021072902");
  58.        System.out.println(students.toString());
  59.   }
  60.     @Test
  61.     public void test08 (){ //模糊查询一个学生信息 一个集合参数 mapper文件中按照key取值
  62.         SqlSession sqlSession = factory.openSession( true);
  63.         StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
  64.        HashMap<String, String> map = new HashMap<>();
  65.        map.put( "stuname", "li");
  66.        map.put( "stuno", "2021072902");
  67.        List<Student> students = studentDao.selectLikeName3(map);
  68.        System.out.println(students.toString());
  69.   }
  70. }

Mybatis的获取参数的方式

方式1:${} 字符串拼接

方式2:#{} 占位符

1.Mapper接口参数为单个参数


  
  1. <delete id="delUserById" parameterType="int">
  2.        delete from user where id = #{id}
  3. </delete>
  4.   <delete id="delUserById" parameterType="int">
  5.        delete from user where id = ${id}
  6. </delete>
 注:如何参数是String类型使用${}获取参数是需要手动添加引号 ''

2.Mapper接口参数是多个参数的获取

mybatis在处理多个参数时,会将多个参数保存到map集合中会 以 agr0 ,agr1或param1 param2为键 以参数位置进行存储


  
  1. User selectUserByUserNameAndPassword(String username,String password);
  2. <select id="selectUserByUserNameAndPassword" resultType="user">
  3.        select  * from user where user_name = #{arg0} and password = #{arg1}
  4. </select>

3.将参数设为map集合进行数据的传递


  
  1. User selectUserByMap(Map map);
  2. <select id="selectUserByMap" resultType="cn.kgc.mybatis.entity.User">
  3.        select  * from user where user_name = #{username} and password = #{password}
  4. </select>

4.通过注解@param("键名")设置参数的获取名字


  
  1. User selectUserByUserNameAndPassword(@param("username")String username,(@param("password")String password);
  2. <select id="selectUserByUserNameAndPassword" resultType="user">
  3.        select  * from user where user_name = #{username} and password = #{password}
  4. </select>
  5. 或者
  6. <select id="selectUserByUserNameAndPassword" resultType="user">
  7.        select  * from user where user_name = #{param1} and password = #{param2}
  8. </select>

5.将多个参数设置成对象进行数据的传递


  
  1. int insertUser(User user);
  2. <insert id="insertUser" parameterType="user" useGeneratedKeys="true" keyProperty="id" >
  3.         insert into user values ( #{id},#{userName},#{password})
  4. </insert>

Mybatis中的模糊查询

方式1:

SELECT * FROM tableName WHERE name LIKE #{text}
​
-- 传递的参数需要拼接  ‘%text%’

方式2:

SELECT * FROM tableName WHERE name LIKE '%${text}%';
 -- 使用$替代# 参数无需在拼接%  存在sql注入

方式3

SELECT * FROM tableName WHERE name LIKE CONCAT('%', #{text}), '%');
-- 使用mysql的函数  实现拼接

6.批量删除


  
  1. int deleteMore(String ids);
  2.   <delete id="deleteMore">
  3.        delete from user where id in(${ids})
  4.   </delete>

mapper中自定义映射

自定义映射的用法之一,解决表格查询的字段名和实体类中不一致的情况


  
  1. <resultMap id="userMap" type="user">
  2.         <id column="id" property="id"> </id>
  3.         <result column="user_name" property="userName"> </result>
  4.         <result column="password" property="password"> </result>
  5. </resultMap>

mybatis对象的关联关系

一对多关系处理(一方)


  
  1. <resultMap id="selectByEIdMap" type="cn.kgc.mybatis.entity.Emp">
  2.         <result column="id" property="dept.id" > </result>
  3.         <result column="dname" property="dept.dName"> </result>
  4. </resultMap>
  5.     <resultMap id="selectByEIdMap2" type="cn.kgc.mybatis.entity.Emp">
  6.         <id column="eid" property="eId"> </id>
  7.         <result column="ename" property="EName"> </result>
  8.         <result column="age" property="age"> </result>
  9.         <result column="deptno" property="deptNo"> </result>
  10.         <!--实体对象标识-->
  11.       <association property="dept" javaType="dept">
  12.           <id column="id" property="id"> </id>
  13.           <result column="dname" property="dName"> </result>
  14.       </association>
  15.     </resultMap>
  16. <!-- 分步查询 -->
  17.     <resultMap id="selectByEIdMap3" type="cn.kgc.mybatis.entity.Emp">
  18.         <id column="eid" property="eId"> </id>
  19.         <result column="ename" property="EName"> </result>
  20.         <result column="age" property="age"> </result>
  21.         <result column="deptno" property="deptNo"> </result>
  22.         <association property="dept" select="cn.kgc.mybatis.mapper.DeptMapper.selectById"
  23.                                     column= "deptno"
  24.                                   fetchType= "eager">
  25.         </association>
  26.     </resultMap>
  27. 注:延迟加载设置 :
  28. 1. <setting name="lazyLoadingEnabled" value="true"/>
  29. 2. <setting name="aggressiveLazyLoading" value="false"/>  3.4.1之前的版本需要设置
  30.     <select id="selectByEId" resultMap="selectByEIdMap2">
  31.            select  * from emp left  join dept on emp.deptno = dept.id  where eid = #{eid}
  32.     </select>
  33.     <select id="selectByEId2" resultMap="selectByEIdMap3">
  34.            select  * from emp  where eid = #{eid}
  35.     </select>

一对多关系处理(多方)


  
  1. <resultMap id="BaseResultMap" type="cn.kgc.mybatis.entity.Dept">
  2.             <id property="id" column="id" />
  3.             <result property="dName" column="dname" />
  4.             <collection property="emps" ofType="emp">
  5.                 <id column="eid" property="eId"> </id>
  6.                 <result column="ename" property="EName"> </result>
  7.                 <result column="age" property="age"> </result>
  8.                 <result column="deptno" property="deptNo"> </result>
  9.             </collection>
  10.     </resultMap>
  11.     <resultMap id="BaseResultMap2" type="cn.kgc.mybatis.entity.Dept">
  12.         <id property="id" column="id" />
  13.         <result property="dName" column="dname" />
  14.         <collection property="emps" select="cn.kgc.mybatis.mapper.EmpMapper.selectByDeptId" column="id"> </collection>
  15.     </resultMap>
  16.     <select id="selectById" resultType="dept">
  17.        select  * from dept where id = #{id}
  18.     </select>
  19.     <select id="selectById2" resultMap="BaseResultMap">
  20.        select emp.* ,dept.* from dept left join emp on dept.id = emp.deptno where id = #{id}
  21.     </select>
  22.     <select id="selectById3" resultMap="BaseResultMap2">
  23.        select dept.* from dept  where id = #{id}
  24.     </select>

mybatis动态sql

动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦

动态SQL:if 语句

根据 stu_name 和 stu_sex 来查询数据。如果stu_name为空,那么将只根据stu_sex来查询;反之只根据stu_name来查询

首先不使用 动态SQL 来书写


  
  1. <select id="selectStudent" resultType="student" parameterType="cn.kgc.mybatis.pojo.Student">
  2.    select * from user where stu_name=#{stu_name} and stu_sex=#{stu_sex}
  3. </select>

可以发现,如果 #{stu_name} 为空,那么查询结果也是空,如何解决这个问题呢?使用 if 来判断


  
  1. <select id="selectStudent" resultType="student" parameterType="cn.kgc.mybatis.pojo.Student">
  2.     select * from student where  
  3.     <if test="stu_name != null">
  4.               stu_name=#{stu_name}
  5.     </if>
  6.     <if test="stu_sex!= null">
  7.           and stu_sex=#{stu_sex}
  8.     </if>
  9. </select>

 这样写我们可以看到,如果 sex 等于 null,那么查询语句为 select * from student where stu_name=#{stu_name},但是如果stu_name 为空呢?那么查询语句为 select * from user where and stu_sex=#{sex},这是错误的 SQL 语句,如何解决呢?

if+where 语句


  
  1. <select id="selectStudent" resultType="student" parameterType="cn.kgc.mybatis.pojo.Student">
  2.     select * from student
  3.         <where>
  4.                 <if test="stu_name != null">
  5.                         stu_name=#{stu_name}
  6.                 </if>
  7.                 <if test="stu_sex!= null">
  8.                         and stu_sex=#{stu_sex}
  9.                 </if>
  10.         </where>
  11. </select>

这个where标签会知道如果它包含的标签中有返回值的话,它就插入一个where。此外,如果标签返回的内容是以AND 或OR 开头的,则它会剔除掉

动态SQL:if+set 语句

上面的对于查询 SQL 语句包含 where 关键字,如果在进行更新操作的时候,含有 set 关键词


  
  1. <update id="updateStudentById" parameterType="cn.kgc.mybatis.pojo.Student">
  2.    update student stu
  3.         <set>
  4.             <if test="stuname != null and stuname != ''">
  5.                stu.stu_name = #{stuName},
  6.             </if>
  7.             <if test="stusex != null and stusex != ''">
  8.                stu.stu_sex = #{stuSex}
  9.             </if>
  10.         </set>
  11.     where id=#{id}
  12. </update>
  • 如果第一个条件 username 为空,那么 sql 语句为:update user u set u.sex=? where id=?

  • 如果第一个条件不为空,那么 sql 语句为:update user u set u.username = ? ,u.sex = ? where id=?

动态SQL:choose(when,otherwise) 语句

有时候,我们不想用到所有的查询条件,只想选择其中的一个,查询条件有一个满足即可,使用 choose 标签可以解决此类问题,类似于 Java 的 switch 语句


  
  1. <select id="selectStudentByChoose" resultType="com.ys.po.User" parameterType="com.ys.po.User">
  2.      select * from student
  3.       <where>
  4.           <choose>
  5.               <when test="id !='' and id != null">
  6.                  id=#{id}
  7.               </when>
  8.               <when test="username !='' and username != null">
  9.                  and username=#{username}
  10.               </when>
  11.               <otherwise>
  12.                  and sex=#{sex}
  13.               </otherwise>
  14.           </choose>
  15.       </where>
  16. </select>

这里我们有三个条件,id,username,sex,只能选择一个作为查询条件

  • 如果 id 不为空,那么查询语句为:select * from user where id=?

  • 如果 id 为空,那么看username 是否为空,如果不为空,那么语句为 select * from user where username=?;

  • 如果 username 为空,那么查询语句为 select * from user where sex=?

动态SQL:trim 语句

trim标记是一个格式化的标记,可以完成set或者是where标记的功能

用 trim 改写上面的 if+where 语句


  
  1. <select id="selectStudent" resultType="student" parameterType="cn.kgc.mybatis.pojo.Student">
  2.     select * from user
  3.       <trim prefix="where" prefixOverrides=" and | or">
  4.             <if test="stu_name != null">
  5.                stu_name=#{stu_name}
  6.             </if>
  7.             <if test="stu_sex!= null">
  8.                and stu_sex=#{stu_sex}
  9.             </if>
  10.       </trim>
  11. </select>
  • prefix:前缀  

  • prefixoverride:去掉第一个and或者是or   

用 trim 改写上面的 if+set 语句


  
  1. <update id="updateStudentById" parameterType="cn.kgc.mybatis.pojo.Student">
  2.    update student stu
  3.       <trim prefix="set" suffixOverrides=",">
  4.             <if test="stuname != null and stuname != ''">
  5.                stu.stu_name = #{stuName},
  6.             </if>
  7.             <if test="stusex != null and stusex != ''">
  8.                stu.stu_sex = #{stuSex}
  9.             </if>
  10.         </trim>
  11.     where id=#{id}
  12. </update>
  • suffix:后缀  

  • suffixoverride:去掉最后一个逗号(也可以是其他的标记,就像是上面前缀中的and一样)

动态SQL: foreach 语句

需求:我们需要查询 user 表中 id 分别为1,2,3的用户,sql语句:


  
  1. select * from user where id = 1 or id = 2 or id = 3
  2. select * from user where id in ( 1, 2, 3)

用 foreach 来改写 select * from user where id=1 or id=2 or id=3


  
  1. <select id="selectUserByListId" parameterType="com.ys.vo.UserVo" resultType="com.ys.po.User">
  2.    select * from user
  3.     <where>
  4.         <!--
  5.           collection:指定输入对象中的集合属性
  6.           item:每次遍历生成的对象
  7.            open:开始遍历时的拼接字符串
  8.            close:结束时拼接的字符串
  9.            separator:遍历对象之间需要拼接的字符串
  10.            select * from user where 1=1 and (id=1 or id=2 or id=3)
  11.          -->
  12.         <foreach collection="ids" item="id" separator="or">
  13.           id=#{id}
  14.         </foreach>
  15.     </where>
  16. </select>

用 foreach 来改写 select * from user where id in (1,2,3)


  
  1. <select id="selectUserByListId" parameterType="com.ys.vo.UserVo" resultType="com.ys.po.User">
  2.        select * from user
  3.         <where>
  4.             <!--
  5.               collection:指定输入对象中的集合属性
  6.               item:每次遍历生成的对象
  7.                open:开始遍历时的拼接字符串
  8.                close:结束时拼接的字符串
  9.                separator:遍历对象之间需要拼接的字符串
  10.                select * from user where1=1 and id in (1,2,3)
  11.              -->
  12.             <foreach collection="ids" item="id" open="id in ("separator="," close=") " >
  13.                #{id}
  14.             </foreach>
  15.         </where>
  16. </select>

动态SQL: SQL 片段

有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用。

假如我们需要经常根据用户名和性别来进行联合查询,那么我们就把这个代码抽取出来,如下:


  
  1. <sql id="selectUserByUserNameAndSexSQL">
  2.     <if test="username != null and username != ''">
  3.        AND username = #{username}
  4.     </if>    
  5.     <if test="sex != null and sex != ''">
  6.        AND sex = #{sex}
  7.     </if>
  8. </sql>
  9. <select id="selectUserByUsernameAndSex" resultType="user" parameterType="com.ys.po.User">
  10.    select * from user
  11.     <trim prefix="where" prefixOverrides="and | or">
  12.         <!-- 引用 sql 片段,如果refid 指定的不在本文件中,那么需要在前面加上 namespace -->
  13.         <include refid="selectUserByUserNameAndSexSQL"> </include>
  14.         <!-- 在这里还可以引用其他的 sql 片段 -->
  15.     </trim>
  16. </select>

注意:①、最好基于 单表来定义 sql 片段,提高片段的可重用性

    ②、在 sql 片段中最好不要包括 where

mybatis注解开发


  
  1. public interface StudentDao2 {
  2.     @Select("select * from student where stu_no = #{stu_no}")
  3.     @Results({
  4.            @Result(property = "stuNo" ,column="stu_no"),
  5.            @Result(property = "stuSex",column = "stu_sex"),
  6.            @Result(property = "birth",column = "stu_birth")
  7.   })
  8.   List<Student> getAll (String stu_no);
  9.     @Insert("insert into student (stu_no,stu_name,stu_sex,stu_birth)values(#{stuNo},#{stuName},#{stuSex},#{birth})")
  10.     int addStudent (Student student);
  11.     @Delete("delete from student where stu_no = #{stu_no}")
  12.     int delOne (String stu_no);
  13.     @Update("update student set stu_name = #{stuName} where stu_no = #{stuNo}")
  14.     int uptStudent (Student student);
  15. }

mybatis缓存

MyBatis 中的缓存就是说 MyBatis 在执行一次SQL查询或者SQL更新之后,这条SQL语句并不会消失,而是被MyBatis 缓存起来,当再次执行相同SQL语句的时候,就会直接从缓存中进行提取,而不是再次执行SQL命令。

mybatis的缓存机制有两级:

(1)一级缓存:一级缓存mybatsi已经为我们自动开启,不用我们手动操作,而且我们是关闭不了的!!但是我们可以手动清除缓存。(SqlSession级别.提交事务,缓存清空)

一级缓存失效的情况:

1.不同的SqlSession对应不同的缓存
2.同一个SqlSession但是查询条件不同
3.同一个SqlSession执行两次相同查询之间做了增删改的操作
4.同一个SqlSession执行两次相同查询之间手动清空缓存

(2)二级缓存:二级缓存需要我们手动开启。(全局级别 SqlSessionFactory)

<!--开启二级缓存-->
​
开启二级缓存需要两个步骤,第一步在mybatis的全局配置文件中配置Setting属性,设置名为cacheEnabled的属性值为true即可
<settings>
        <!-- 
            (1):开启二级缓存,这个全局的配置二级缓存
                   默认是开启的,但是还是需要写上,防止版本的更新 
        -->
        <setting name="cacheEnabled" value="true"/>
</settings> 
​
第二步:在具体需要二级缓存的mapeer映射文件中开启二级缓存,值需要在相应的映射文件中添加一个cache标签即可
2):在相应的映射文件中开启二级缓存
<!-- 开启二级缓存 -->
 <cache></cache>
3)查询数据封装的实体类要实现序列化的接口
4)二级缓存需要在一级缓存关闭或者提交后生效
​
二级缓存失效的条件:
1.在两次查询之间进行了任意的增删改操作,一级二级缓存同时失效
​

  
  1. @Test
  2.     public void test02 (){ //验证mybatis的缓存机制 一级缓存 默认开启 sqlsession级别
  3.         try {
  4.             InputStream resource = Resources.getResourceAsStream( "config/mybatis-config.xml");
  5.             SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resource);
  6.             SqlSession sqlSession = factory.openSession( true);
  7.             StudentDao mapper1 = sqlSession.getMapper(StudentDao.class);
  8.             StudentDao mapper2 = sqlSession.getMapper(StudentDao.class);
  9.            System.out.println(mapper1);
  10.            System.out.println(mapper2);
  11.            List<Student> a1 = mapper1.getAll();
  12.            System.out.println(a1);
  13.             //手动提交事务 清空缓存
  14.            sqlSession.commit();
  15.            List<Student> a2 = mapper2.getAll();
  16.            System.out.println(a2);
  17.            sqlSession.close();
  18.       } catch (IOException e) {
  19.            e.printStackTrace();
  20.       }
  21.   }
  22.     @Test
  23.     public void test03 (){ //验证mybatis的缓存机制 二级缓存 需要配置mybatis-config.xml 和mapper文件
  24.         try {
  25.             InputStream resource = Resources.getResourceAsStream( "config/mybatis-config.xml");
  26.             SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resource);
  27.             SqlSession sqlSession1 = factory.openSession( true);
  28.             SqlSession sqlSession2 = factory.openSession( true);
  29.             SqlSession sqlSession3 = factory.openSession( true);
  30.             StudentDao mapper1 = sqlSession1.getMapper(StudentDao.class);
  31.             StudentDao mapper2 = sqlSession2.getMapper(StudentDao.class);
  32.             StudentDao mapper3 = sqlSession3.getMapper(StudentDao.class);
  33.            List<Student> a1 = mapper1.getAll();
  34.            System.out.println(a1);
  35.             //关闭session将查询结果写入二级缓存
  36.            sqlSession1.close();
  37.             //当对同一张表进行增删改操作后 二级缓存清除
  38.            mapper3.delStudent( "2021072901");
  39.           // sqlSession3.close();
  40.            List<Student> a2 = mapper2.getAll();
  41.            System.out.println(a2);
  42.       } catch (IOException e) {
  43.            e.printStackTrace();
  44.       }
  45.   }

mybatis分页插件


  
  1. <!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
  2. <dependency>
  3.     <groupId>com.github.pagehelper </groupId>
  4.     <artifactId>pagehelper </artifactId>
  5.     <version>5.2.1 </version>
  6. </dependency>
<!--在mybatis配置文件中 配置mybatis插件 -->

  
  1. <plugins>
  2. <plugin interceptor="com.github.pagehelper.PageInterceptor">
  3. <!-- 配置mysql方言 -->
  4. <property name="helperDialect" value="mysql" />
  5. <!-- 设置为true时,如果pageSize=0就会查询出全部的结果 -->
  6. <property name="pageSizeZero" value="true" />
  7. <!-- 3.3.0版本可用,分页参数合理化,默认false禁用 -->
  8. <!-- 启用合理化时,如果pageNum<1会查询第一页,如果pageNum>pages会查询最后一页 -->
  9. <!-- 禁用合理化时,如果pageNum<1或pageNum>pages会返回空数据 -->
  10. <property name="reasonable" value="true" />
  11. </plugin>
  12. </plugins>

实例

 // 测试分页插件的使用

  
  1.     @Test
  2.     public void   test06 (){
  3.         SqlSession session = factory.openSession( true);
  4.         StudentDao mapper = session.getMapper(StudentDao.class);
  5.        PageHelper.startPage( 5, 3);
  6.        List<Student> all = mapper.findAll();
  7.        PageInfo<Student> pageInfo = new PageInfo<>(all);
  8.         //获取分页的相关数据
  9.        System.out.println(pageInfo);
  10.         //获取总条数
  11.         long total = pageInfo.getTotal();
  12.        System.out.println(total);
  13.         //获取当前页的显示数据
  14.        List<Student> list = pageInfo.getList();
  15.        list.forEach(student-> System.out.println(student));
  16.   }


转载:https://blog.csdn.net/m0_67979925/article/details/128975590
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场