java回顾:mybatis注解开发、mybatis基于注解实现动态SQL、延迟加载、Mybatis缓存

目录

一、mybatis注解开发

1、搭建注解开发的Mybatis环境

1、插入

2、删除

3、更新

4、查询

5、自增主键回填

6、结果集映射(@Results实现映射)

二、mybatis基于注解实现动态SQL

1、动态sql(脚本标签)@ResultMap指定映射

2、动态SQL  @SelectProvider

三、注解开发 延迟加载

四、Mybatis缓存

1、一级缓存 

1.1 测试一级缓存

1.2  一级缓存失效

2、二级缓存

1.1 二级缓存原理

1.2  二级缓存条件

1.3 测试二级缓存


一、mybatis注解开发

      mybatis的SQL映射文件可以使用xml的方式配置,但不同的用户模块接口都对应一个映射文件,并且在映射文件中书写sql语句很麻烦。所以Mybatis为用户提供了快速的开发方式,基于注解(Annnotation)的配置方式。 

@Insert:保存  
         Value:sql语句(和xml的配置方式一模一样)
@Update:更新 
         Value:sql语句      
@Delete: 删除
         Value:sql语句     
@Select: 查询
         Value:sql语句  
@Options:可选配置(获取主键)
         userGeneratedKeys:开关,值为true表示可以获取主键  相当于select last_insert_id()
         keyProperty     :对象属性
         keyColumn       : 列名

1、搭建注解开发的Mybatis环境

将mybatis全局配置文件mybatis-config.xml中的mapper路径改为包扫描或者class路径

说明:因为没有了映射文件,所以我们这里采用加载接口方式,需要告知mybatis哪个接口的方法上的注解需要被执行。

  • 配置核心配置文件
    
    
        
        
        
        
    
  • 定义接口
public interface UserMapper {
    @Insert("insert into tb_user values(null,#{userName},#{password},#{name},#{age},#{sex})")
    Integer addUser(User user);
}

1、插入

定义接口后,编写测试

    //myBatis注解开发@insert
    @Test
    public void t1() {
        final SqlSession session = SessionFactoryUtils.getSession();
        final UserMapper mapper = session.getMapper(UserMapper.class);
        final User2 user2 = new User2(null,null,"buzz","666","巴斯光年",18,1);
        final Integer integer = mapper.addUser(user2);
        System.out.println("添加用户 = " + integer);
        session.close();
    }

2、删除

 在根据id删除数据的方法上面编写注解@Delete

    @Delete("delete from tb_user where id = #{id}")
    Integer deleteUser(@Param("id") Integer id);
    //myBatis注解开发@delete
    @Test
    public void t2() {
        final SqlSession session = SessionFactoryUtils.getSession();
        final UserMapper mapper = session.getMapper(UserMapper.class);
        final Integer integer = mapper.deleteUser(13);
        System.out.println("添加用户 = " + integer);
        session.commit();
        session.close();
    }

3、更新

//在根据id修改用户数据方法上面添加注解@Update,然后在其value属性值中编写具体的SQL
@Update("update tb_user set user_name=#{userName},password=#{password},name=#{name},age=#{age},sex=#{sex} where id=#{id}")
Integer updateUser(User2 user2);
    @Test
    public void t3() {
        final SqlSession session = SessionFactoryUtils.getSession();
        final UserMapper mapper = session.getMapper(UserMapper.class);
        final User2 user2 = new User2(null,14L,"buzzLightYear","666","巴斯光年飞向太空",18,1);
        final Integer integer = mapper.updateUser(user2);
        System.out.println("integer = " + integer);
        session.commit();
        session.close();
    }

4、查询

若不开启驼峰映射,有些值拿不到。

    //查询所有用户
    @Select("select * from tb_user")
    List findAll();
    //myBatis注解开发@select
    @Test
    public void t4() {
        final SqlSession session = SessionFactoryUtils.getSession();
        final UserMapper mapper = session.getMapper(UserMapper.class);
        final List all = mapper.findAll();
        System.out.println("all = " + all);
        session.commit();
        session.close();
    }

5、自增主键回填

 自增主键回填(了解):使用注解完成数据新增,新增成功后返回数据的主键id值

    @Insert("insert into tb_user values(null,#{userName},#{password},#{name},#{age},#{sex})")
    @Options(useGeneratedKeys = true,keyColumn = "id" ,keyProperty = "id")
    Integer addUserAndGetFk(User2 user);
    //myBatis注解开发:自增主键回填
    @Test
    public void t5() {
        final SqlSession session = SessionFactoryUtils.getSession();
        final UserMapper mapper = session.getMapper(UserMapper.class);
        final User2 user2 = new User2(null,null,"wudy","666","胡迪",18,1);
        final Integer integer = mapper.addUserAndGetFk(user2);
        System.out.println("integer = " + integer);
        //此时已经拿到返回的id
        System.out.println(user2.getId());
        session.commit();
        session.close();
    }

 6、结果集映射(@Results实现映射

        根据之前的学习,如果数据表的列名和pojo实体类的属性名不一致,会导致数据表的数据无法封装到实体类属性值中,对此我们有如下解决方案:

使用注解:@Results实现映射(等价于标签)。

目标:使用注解的方式给取别名后的字段,映射到实体类中,并查询所有用户信息; ​

注意:为方便演示效果,可将之前核心配置文件中的开启驼峰自动映射设置为false

注意:此处 @Results的id="userMap2",id名不要冲突。

    @Select("select * from tb_user where id=#{id}")
    @Results(id="userMap2",value = {
            @Result(column = "id",property = "id",id=true),
            @Result(column = "user_name",property = "userName")})
    User2 findById(Long id);
    //myBatis注解开发:自增主键回填
    @Test
    public void t6() {
        final SqlSession session = SessionFactoryUtils.getSession();
        final UserMapper mapper = session.getMapper(UserMapper.class);
        final User2 byId = mapper.findById(1L);
        System.out.println("byId = " + byId);
        session.commit();
        session.close();
    }

二、mybatis基于注解实现动态SQL

1、动态sql(脚本标签)@ResultMap指定映射

查询男性用户,如果输入了用户名,按用户名模糊查询,如果没有输入用户名,就查询所有男性用户:

        在接口上添加: 标签,标签体中编写sql语句,sql语句与之前XML配置文件中的一致即可;这种方式在写法上面和 XML 中的写法是一样,支持 XML 的动态SQL语法,可以在上面的字符串中写 等 标签的语法。 

注意:接口注解中要指定mapper.xml的映射id@ResultMap(value = "userAndOrderMap")

    @Select("")
    @ResultMap(value = "userAndOrderMap")
    List findUserByName(@Param("name") String name);
    //myBatis注解开发:脚本标签:查询男性用户,如果输入了用户名,按用户名模糊查询,如果没有输入用户名,就查询所有男性用户
    @Test
    public void t7() {
        final SqlSession session = SessionFactoryUtils.getSession();
        final UserMapper mapper = session.getMapper(UserMapper.class);
        final List userByName = mapper.findUserByName("%zhang%");
        System.out.println("userByName = " + userByName);
        session.commit();
        session.close();
    }

2、动态SQL  @SelectProvider

查询男性用户,如果输入了用户名,按用户名模糊查询,如果没有输入用户名,就查询所有男性用户:

        使用 @SelectProvider 注解,注解中的type 参数是提供构建 SQL 的类,method 是构建 SQL 的方法。 构建 SQL 的方法的参数要和接口的参数一致,并且多个参数要使用@Param命名参数。

    @SelectProvider(type = SqlProvider.class,method = "findUserByName")
    @ResultMap(value = "userAndOrderMap")
    List findUserByName2(@Param("name") String name);

sql类: 

public class SqlProvider {
    public String findUserByName(@Param("name") String name){
        String sql="select * from tb_user where sex=1";
        if(name!=null){
            sql+=" and user_name like #{name}";
        }
        return sql;
    }
}
    //myBatis注解开发:SelectProvider查询男性用户,如果输入了用户名,按用户名模糊查询,如果没有输入用户名,就查询所有男性用户
    @Test
    public void t8() {
        final SqlSession session = SessionFactoryUtils.getSession();
        final UserMapper mapper = session.getMapper(UserMapper.class);
        final List userByName = mapper.findUserByName2("%zhang%");
        System.out.println("userByName = " + userByName);
        session.commit();
        session.close();
    }

三、注解开发 延迟加载

四、Mybatis缓存

  •         缓存就是用来提高查询访问速度,将每次的访问记录缓存在一地方,在下次进行查询时首先访问的不是数据库,而是缓存,若在缓存中查询到了该次查询条件的结果集就直接返回结果,不再访问数据库。这样就对数据库的操作次数上就减少了很多,从而提高访问速度。
  • 当然,在查询缓存的机制中有两种不同的作用域(生命周期),分别是一级缓存与二级缓存。

1、一级缓存 

  • MyBatis的一级查询缓存是由 org.apache.ibatis.cache.impl.PerpetualCache 类的 HashMap本地缓存实现的,它的作用域则是SqlSession,它的作用域也就是生命周期;
  • 假如同一个SqlSession中执行两次sql语句的查询,这两次的查询的位置是不同的,第一次查询时,由于没有缓存结果则是从数据库中进行查询结果,得到结果后写入缓存并将结果返回给查询语句,而在进行第二次查询时,这时缓存中已经有符合条件的结果集,这次的查询就会在缓存获得结果并返回,而不会向数据库进行查询。当SqlSession结束后相应的缓存也就销毁了。
  • myBatis默认一级缓存,查询时开启状态;
1.概念:一级缓存属于本地缓存,SqlSession级别的;
2.原理:        
        1)在同一个SqlSession,发生了一次查询,查询的结果会存入一级缓存;        
        2)第二次再发生相同查询时,直接从缓存中获取数据,不再与数据库建立连接查询数据;
3.注意:一级缓存,默认是开启的,无法关闭。

1.1 测试一级缓存

完成根据id查询用户数据:

测试步骤:用同一个session根据id查询用户2次,然后查看日志打印sql的情况进行判断判断;

1)在相同的sqlsession下调用mapper接口执行2次查询,第二次数据从一级缓存中获取; 

    @Test
    public void t8() {
        final SqlSession session = SessionFactoryUtils.getSession();
        final UserMapper mapper = session.getMapper(UserMapper.class);
        final List userByName = mapper.findUserByName2("%zhang%");
        System.out.println("userByName = " + userByName);
        final List userByName2 = mapper.findUserByName2("%zhang%");
        System.out.println("userByName2 = " + userByName2);
        session.commit();
        session.close();
    }

java回顾:mybatis注解开发、mybatis基于注解实现动态SQL、延迟加载、Mybatis缓存_第1张图片

仅执行一遍。 

2)开启两个session,调用相同的方法,查看sql执行次数;

public class TestAll2 {
    private static SqlSession session1;
    private static SqlSession session2;

    static {
        InputStream in = null;
        try {
            in = Resources.getResourceAsStream("mybatisZhuJie.xml");
        } catch (IOException e) {
            e.printStackTrace();
        }
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in);
        session1=sessionFactory.openSession();
        session2=sessionFactory.openSession();
    }

    @Test
    public void test1(){
        UserMapper mapper1 = session1.getMapper(UserMapper.class);
        UserMapper mapper2 = session2.getMapper(UserMapper.class);
        final User2 byUserId = mapper1.findByUserId(1L);
        System.out.println("byUserId = " + byUserId);
        final User2 userById = mapper2.findByUserId(1L);
        System.out.println("userById = " + userById);
    }
}

java回顾:mybatis注解开发、mybatis基于注解实现动态SQL、延迟加载、Mybatis缓存_第2张图片

说明:一级缓存是session级别,sessin与session之间不能共享缓存;

1.2  一级缓存失效

1)查询条件不一致

 说明:相同的session下可根据id=1和id=2去查询,发现需要查询2次;

@Test
public void test3(){
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    User user = userMapper.findById(1l);
    System.out.println(user);
    //说明:两次查询,条件不一样,不会被缓存名称,此时应该打印两次sql
    User user2 = userMapper.findById(2l);
    System.out.println(user2);
}

2)sqlSession不同

 说明:获取两个sesion,然后在两个sesion中获取相同类型的动态代理对象,进行测试;

3)两次查询期间存在增删改操作

说明:在执行update、insert、delete的时候,即使操作的不是和一级缓存中的是同一条记录,都会清空一级缓存。

@Test
public void test15(){
    UserMapper userMapper = MybatisUtil.getMapper(UserMapper.class);
    //1.根据用户ID查询用户信息 一级缓存中没有数据,那么就会去数据库查询(发送sql)
    User user = userMapper.findById(1L);
    //2.当当前session发生增删改操作,就会清除一级缓存    
    userMapper.deleteByUserId(13);
    //3.此时因为一级缓存中数据被清空了,所以需要从数据库再次查询
    User user2 = userMapper.findById(1L);
    System.out.println(user);
    System.out.println(user2);
}

 4)手动清除一级缓存

 使用:sqlSession.clearCache();可以强制清除缓存;

@Test
public void test6(){
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    //共打印2次sql
    User user = userMapper.findById(12l);
    System.out.println(user);
    //清空当前session下的一级缓存
    sqlSession.clearCache();
    //此时需要再次去数据库查询
    User user2 = userMapper.findById(12l);
    System.out.println(user2);
}

2、二级缓存

概念:全局缓存 ,namespace级别;

mybatis 的二级缓存的作用域:mapper范围的(即映射文件级别的,多个sqlSession可以共享二级缓存数据); 

1.1 二级缓存原理

  • 在一个sqlSession,进行了一次查询,会把查询结果存入一级缓存;
  • 当sqlSession关闭之后,mybatis会把一级缓存中的数据存入二级缓存中;
  • 当再次发生相同的查询时,会从二级缓存中命中;
  • 场景:在用户通过id查询一个商品信息,执行完查询方法之后会将sqlSession释放掉,当再次发送请求查询同一个商品信息时会再次获取一个  sqlSession来执行查询,那么此时如果配置了二级缓存的话,就可以直接从二级缓存中获取信息,而不用再次去数据库查询了。

1.2  二级缓存条件

 1)手动开启

1.全局配置中: 默认已开启。
映射文件中:
2.注解方式:或者在接口上添加注解 @CacheNamespace

2)第一个session必须关闭

        说明:由于缓存数据是在sqlSession调用close方法时,放入二级缓存的,因此在测试二级缓存时必须先将第一个sqlSession关闭;

3)二级缓存的对象必须序列化,如:User对象必须实现Serializable接口。

说明:因为二级缓存的原理就是将对象进行序列化。 

1.3 测试二级缓存

开启二级缓存方式:

  • 在映射文件(UserMapper.xml)中添加;
  • 在Mapper接口添加@CacheNamespace注解开启; 

测试思路:session1获取mapper进行查询,然后关闭session1,session2获取mapper相同条件二次查询;

1)在核心配置文件下开启二级缓存



    
    
    

2)接口下标注开启namespace二级缓存

@CacheNamespace(blocking = true)
public interface UserDao {
    .....
}
    @Test
    public void t8() {
        final SqlSession session = SessionFactoryUtils.getSession();
        final UserMapper mapper = session.getMapper(UserMapper.class);
        final List userByName = mapper.findUserByName2("%zhang%");
        System.out.println("userByName = " + userByName);
        session.close();
        final SqlSession session2 = SessionFactoryUtils.getSession();
        final UserMapper mapper2 = session2.getMapper(UserMapper.class);

        final List userByName2 = mapper2.findUserByName2("%zhang%");
        System.out.println("userByName2 = " + userByName2);
        session2.close();
    }

java回顾:mybatis注解开发、mybatis基于注解实现动态SQL、延迟加载、Mybatis缓存_第3张图片

你可能感兴趣的:(java回顾,mybatis,java,sql)