Mybatis学习笔记——四、缓存,注解实现一对多、多对一和动态sql

7 篇文章 0 订阅
4 篇文章 0 订阅

13、缓存

当我们执行查询的时候,查询的结果会同时存入到SqlSession为我们提供的一块区域中。
该区域的结构是一个Map。当我们再次查询同样的数据,mybatis会先去查询SqlSession中是否有,有的话直接拿来用。
当SqlSession对象消失时,mybatis的一级缓存也就消失了。

  • 二级缓存:
    它指的是mybatis中SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。

二级缓存的使用步骤:

  1. 让mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)
  2. 让当前的映射文件支持二级缓存(在IUserDao.xml中配置)
  3. 让当前的操作支持二级缓存(在select标签中配置)

13.2、一级缓存

其实mybatis中默认就是一级缓存了(平时的测试类就是一级缓存存在SqlSession中)

一级缓存是SqlSession范围的缓存,当调用SqlSession的修改,添加,删除,commit(),close()等方法时,就会清空一级缓存。

13.3、二级缓存

1.SqlMaoConfig.xml中

<settings>
        <setting name="cacheEnabled" value="true"/>
</settings>

2.在需要使用二级缓存的实体类的mapper中

 <!--开启user支持二级缓存-->
    <cache/>

 <!-- 根据id查询用户   注意属性useCache -->
    <select id="findById" parameterType="INT" resultType="user" useCache="true">
        select * from user where id = #{uid}
    </select>

13.4、延迟加载

mybatis中的延迟加载

  • 问题:在一对多中,当我们有一个用户,它有100个账户。
    • 在查询用户的时候,要不要把关联的账户查出来?
    • 在查询账户的时候,要不要把关联的用户查出来?
  • 答案:在查询用户时,用户下的账户信息是,什么时候使用,什么时候查询的。
    • 在查询账户时,账户的所属用户信息应该是随着账户查询时一起查询出来的。

什么是延迟加载?

  • 在真正使用数据时才发起查询,不用的时候不查询。按需加载(懒加载)

什么是立即加载?

  • 不管用不用,只要一调用方法,马上发起查询

采用策略

  • 一对多,多对多:通常情况下我们都是采用延迟加载。
  • 多对一,一对一:通常情况下我们都是采用立即加载。

如何开启?

<settings>
    <!-- 配置全局缓存-->
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="aggressiveLazyLoading" value="true"/>
</settings>

14、注解开发补充

14.1、注解实现多对一(@One)

public interface IAccountDao {

    /**
     * 查询所有账户,并且获取每个账户所属的用户信息
     * @return
     */
    @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"),
            //这个注解是引入主表        FetchType(加载时机)  EAGER(立即加载)
            @Result(property = "user",column = "uid",one=@One(select="com.ajacker.dao.IUserDao.findById",fetchType= FetchType.EAGER))
    })
    List<Account> findAll();
    
   /**
     * 根据用户id查询账户信息
     * @param userId
     * @return
     */
    @Select("select * from account where uid = #{userId}")
    List<Account> findAccountByUid(Integer userId);

}

@One注解将colomn的参数传递给指定方法,以返回的实体类装填该属性

14.2、注解实现一对多(@Many)

public interface IUserDao {

    /**
     * 查询所有用户
     * @return
     */
    @Select("select * from user")
    @Results(id="userMap",value={
            @Result(id=true,column = "id",property = "userId"),
            @Result(column = "username",property = "userName"),
            @Result(column = "address",property = "userAddress"),
            @Result(column = "sex",property = "userSex"),
            @Result(column = "birthday",property = "userBirthday"),
            @Result(property = "accounts",column = "id",
                    many = @Many(select = "com.itheima.dao.IAccountDao.findAccountByUid",
                                fetchType = FetchType.LAZY))
    })
    List<User> findAll();

    /**
     * 根据id查询用户
     * @param userId
     * @return
     */
    @Select("select * from user  where id=#{id} ")
    @ResultMap("userMap")
    User findById(Integer userId);

}

@Many注解将colomn的参数传递给指定方法,以返回的实体类集合装填该属性

14.3、注解开启二级缓存(@CacheNameSpace)

哪个Dao接口需要就写在哪儿

@CacheNamespace(blocking = true)

14.4、注解实现动态sql

第一种:将xml配置文件居中的语句以<script>标签包裹写在注解内,例如:

	@Select("<script>"
			+ "SELECT "
			+ "a.id as 'id',a.create_date as 'createDate',a.content as 'content',"
			+ "a.parent_id as 'parentId',a.first_comment_id as 'firstCommentId',"
			+ "b.id as 'fromUser.id',b.realname as 'fromUser.realname',b.avatar as 'fromUser.avatar',"
			+ "c.id as 'toUser.id',c.realname as 'toUser.realname',c.avatar as 'toUser.avatar' "
			+ "FROM t_demand_comment a "
			+ "LEFT JOIN t_user b ON b.id = a.from_uid "
			+ "LEFT JOIN t_user c ON c.id = a.to_uid "
			+ "WHERE a.demand_id = #{demandId} "
			+ "ORDER BY a.create_date ASC "
			+ "<if test='startNo!=null and pageSize != null '>"
			+ "LIMIT #{startNo},#{pageSize}"
			+ "</if>"
			+ "</script>")
	public List<DemandComment> listDemandComment(@Param("demandId") Long demandId, @Param("startNo") Integer pageNo, @Param("pageSize") Integer pageSize);

第二种:使用@SelectProvider提供sql

例如:

  • mapper:

    public interface StudentMapper {
    
        @SelectProvider(type = StudentSqlProvider.class, method="select")
        List<Student> findAll(Student student) throws Exception;
        
        @InsertProvider(type = StudentSqlProvider.class , method = "insertStudent" )
        void insert(Student student) throws Exception;
        
        @DeleteProvider(type = StudentSqlProvider.class, method = "delete")
        void delete(Student student) throws Exception;
    
        @UpdateProvider(type = StudentSqlProvider.class, method = "update")
        void update(Student student) throws Exception;
        
    }
    
  • Provider:

    /**
     * Created with IDEA
     * author:bigStone
     * Date:2019/5/2
     **/
    public class StudentSqlProvider {
    
        //插入
        public String insertStudent(Student student) {
            SQL sql = new SQL();
            sql.INSERT_INTO("student");
            if (student.getId() != null) {
                sql.VALUES("id", "#{id}");
            }
            if (student.getUsername() != null) {
                sql.VALUES("username", "#{username}");
            }
            if (student.getPassword() != null) {
                sql.VALUES("password", "#{password}");
            }
            if (student.getAddr() != null) {
                sql.VALUES("addr", "#{addr}");
            }
            return sql.toString();
        }
    
        //查询
        public String select(Student student) {
            return new SQL() {{
                SELECT("id, username, password, addr");
                FROM("student");
                if (student != null) {
                    if (student.getId() != null) {
                        WHERE("id = #{id}");
                    }
                    if (student.getUsername() != null) {
                        WHERE("username like '%' || #{username} || '%'");
                    }
                    if (student.getPassword() != null) {
                        WHERE("password = #{password}");
                    }
                    if (student.getAddr() != null) {
                        WHERE("addr like '%' || #{addr} || '%' ");
                    }
                }
            }}.toString();
        }
    
        //删除
        public String delete(Student student) {
            return new SQL() {{
                DELETE_FROM("student");
                if (student.getId() != null) {
                    WHERE("id = #{id}");
                }
            }}.toString();
        }
    
        //更新
        public String update(Student student) {
            return new SQL() {{
                UPDATE("student");
                if (student.getUsername() != null) {
                    SET("username = #{username}");
                }
                if (student.getPassword() != null) {
                    SET("password = #{password}");
                }
                if (student.getAddr() != null) {
                    SET("addr = #{addr}");
                }
                WHERE("id = #{id}");
            }}.toString();
        }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值