MyBatis小结

MyBatis

MyBatis官方文档:https://mybatis.org/mybatis-3/zh/index.html

Maven依赖


    org.mybatis
    mybatis
    x.x.x

XML配置

配置项(顺序固定)

  • configuration(配置)
    • properties(属性)
    • settings(设置)
    • typeAliases(类型别名)
    • typeHandlers(类型处理器)
    • objectFactory(对象工厂)
    • plugins(插件)
    • environments(环境配置)
      • environment(环境变量)
        • transactionManager(事务管理器)
        • dataSource(数据源)
    • databaseIdProvider(数据库厂商标识)
    • mappers(映射器)

properties(属性)

既可引入外部配置文件也可内部配置

config.properties:
    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8
    username=root
    password=123456


    
    

...

    
    
    
    

加载顺序,后加载的覆盖先加载的

  1. properties 元素体内
  2. properties 引入
  3. 方法参数传递

类型别名(typeAliases)

  1. 为每个类设置别名

     
         
     
  2. 指定包名,没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名

     
         
     
  3. 内置别名

    • 基本数据类型前面加上下划线如:_int 对应 int
    • 引用数据类型小写如:int 对应 Integer

mappers(映射器)

  1. 引入资源方式

     
     
         
     
    
     
     
         
     
    
     
     
         
     
    
     
     
         
     
  2. mapper文件

     
     
     
    
     

Maven静态资源过滤问题

当把xml文件放在src目录下时会出现

解决方法


    
        
            src/main/java
            
                **/*.properties
                **/*.xml
            
            true
        
    

结果集映射

简单结果集映射


    
    
    
    
    


多对一

所有学生(Student)对应同一个老师(Teacher)

按结果嵌套处理(常用)




    
    
    
    
        
    

按查询嵌套处理



    
    


一对多

一个老师拥有多个学生

按结果嵌套处理




    
    
        
        
        
    

按查询嵌套处理



    
    

动态SQL

if

choose (when, otherwise)

trim (where, set)

trim定制成where


...


    update Author
        
            username=#{username},
            password=#{password},
            email=#{email},
            bio=#{bio}
        
    where id=#{id}

trim定制成set


...

foreach

注解开发

简单映射

//Results可以用id命名,这里命名为studentMap,在其他方法中可以直接调用
@Select("select * from student")
@Results(id = "studentMap",value = {
    @Result(id=true,column = "sid",property = "sid"),
    @Result(column = "sname",property = "sname"),
    @Result(column = "sex",property = "sex")
})
List findAll();

//直接调用已有的映射
@Select("select * from student where sid=#{id}")
@ResultMap("studentMap")
Student findById(Integer integer);

插入数据后返回id问题,两种方式

  1. options,添加表的列名sid,指定成员变量的名id,设置useGeneratedKeys = true

  2. selectkey,基本的思路和xml配置一样,代码编写如下:

     @Insert("insert into student(sname,sex,birthday,cno) values(#{name},#{sex})")
     //@Options(useGeneratedKeys = true,keyColumn = "sid",keyProperty = "id")
     @SelectKey(statement = "select last_insert_id()",keyProperty = "id", keyColumn = "sid",resultType = int.class,before = false)
     void addStudent(Student student);

多对一

@One 注解(一对一)代替了标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。

@One 注解属性介绍:

  • select 指定用来多表查询的 sqlmapper
  • fetchType 会覆盖全局的配置参数 lazyLoadingEnabled。。

使用格式:@Result(column=" ",property="",one=@One(select=""))

@Select("select * from account")
@Results(id="accountMap",
    value= {
        @Result(id=true,column="id",property="id"),
        @Result(column="uid",property="uid"),
        @Result(column="money",property="money"),
        @Result(column="uid",
            property="user",
            one=@One(select="com.dao.IUserDao.findById",
        fetchType=FetchType.LAZY)
        )
    })
List findAll();


@Select("select * from user where id = #{uid} ")
@ResultMap("userMap")
User findById(Integer userId);

一对多

@Many 注解(多对一)代替了标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。

注意:聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,属性的 javaType(一般为 ArrayList)但是注解中可以不定义;

使用格式:@Result(property="",column="",many=@Many(select=""))

@Select("select * from user")
@Results(id="userMap",
    value= {
        @Result(id=true,column="id",property="userId"),
        @Result(column="username",property="userName"),
        @Result(column="sex",property="userSex"),
        @Result(column="id",property="accounts",
            many=@Many(
                select="com.dao.IAccountDao.findByUid",
                fetchType=FetchType.LAZY
                )
            )
    })
List findAll();

说明:
@Many:
    相当于的配置
    select 属性:代表将要执行的 sql 语句
    fetchType 属性:代表加载方式,一般如果要延迟加载都设置为 LAZY 的值


@Select("select * from account where uid = #{uid} ")
List findByUid(Integer userId);

二级缓存

@CacheNamespace(blocking=true)//mybatis 基于注解方式实现配置二级缓存
public interface IUserDao {}

动态SQL

script

要在带注解的映射器接口类中使用动态 SQL,可以使用 script 元素。比如:

@Update({""})
void updateAuthorValues(Author author);

bind

bind 元素可以从 OGNL 表达式中创建一个变量并将其绑定到上下文。比如:

SQL片段

提取SQL片段


    
        title = #{title}
    
    
        and author = #{author}
    

引用SQL片段:

缓存

一级缓存

SqlSession级别的缓存,也称为本地缓存,默认开启

一级缓存失效的的四种情况

  1. SqlSession不同
  2. SqlSession相同,查询条件不同
  3. SqlSession,两次查询之间执行了增删改操作
  4. SqlSession相同,手动清除一级缓存 clearCache()

二级缓存

使用步骤

  1. 在配置文件中开启全局缓存 【mybatis-config.xml】

     
  2. 在需要的mapper.xml中配置使用二级缓存【xxxMapper.xml】

     
    • 映射语句文件中的所有 select 语句的结果将会被缓存。
    • 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
    • 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
    • 缓存不会定时进行刷新(也就是说,没有刷新间隔)。
    • 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
    • 缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。

    配置二级缓存

     

    这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。

知识点

MyBatis的优点?为什么用MyBatis而不用JDBC

解除SQL和代码的耦合,提供xml标签,支持编写动态SQL,支持对象与数据库的字段关系映射

#{}和${}的区别

  1. #{}是预编译处理,${}是字符串替换
  2. 处理#{}时,会将SQL中的#{}替换为?号,调用PreparedStatement的set方法赋值,防止SQL注入
  3. 处理${}时,直接将${}替换成变量的值
  4. 排序时使用order by 动态参数时需要注意,用$而不是#

模糊查询like语句写法

  1. 在Java代码中添加通配符%
  2. 在sql中拼接
    1. 使用${...}like '%${value}%'
    2. 使用#{...}"%"#{value}"%"

Mapper 接口的工作原理

Mapper 接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Mapper接口生成代理对象proxy,代理对象会拦截接口方法,转而执行MapperStatement所代表的sql,然后将sql执行结果返回。

如何获取自动生成的(主)键值?

如果采用主键自增长策略,自动生成的键值在insert执行完后被设置到传入的参数对象中,需要加上配置:

传递多个参数的方法

  1. 顺序传参

     public User selectUser(String name, int deptId);
     
  2. @Param注解传参

     public User selectUser(@Param("userName") String name, @Param("deptId") int deptId);
     
  3. Map传参

     public User selectUser(Map params);
     
  4. Java Bean传参

     public User selectUser(User user);
     

结合Spring时一级缓存会失效

SqlSession交给了Spring管理,Spring在使用完后就会关闭

二级缓存的坑

二级缓存是mapper级别,当不同的mapper操作同一个数据时就会产生数据不一致

MyBatis原理

参考文章:MyBatis原理分析(通俗易懂)

如何构建一个线程安全的SqlSession

利用ThreadLocal获取或者关闭SqlSession对象,实现每一个线程都有自己的一个SqlSession对象。

TheadLocal 线程局部变量

ThreadLocal 的作用和目的:用于实现线程内的数据共享,即对于相同的程序代码,多个模块在同一个线程中运行时要共享一份数据,而在另外线程中运行时又共享另外一份数据。

每个线程调用全局 ThreadLocal 对象的 set 方法,在 set 方法中,首先根据当前线程获取当前线程的 ThreadLocalMap 对象,然后往这个 map 中插入一条记录,key 其实是 ThreadLocal 对象,value 是各自的 set 方法传进去的值。也就是每个线程其实都有一份自己独享的 ThreadLocalMap对象,该对象的 Key 是 ThreadLocal 对象,值是用户设置的具体值。在线程结束时可以调用 ThreadLocal.remove()方法,这样会更快释放内存,不调,用也可以,因为线程结束后也可以自动释放相关的 ThreadLocal 变量。

你可能感兴趣的:(MyBatis小结)