• MyBatis-Day4


    1、Mybatis中的延迟加载

    问题:在一对多中,当我们有一个用户,它有100个账户。

    在查询用户的时候,要不要把关联的账户查出来?
    在查询账户的时候,要不要把关联的用户查出来?

    在查询用户时,用户下的账户信息应该是,什么时候使用,什么时候查询账户的,而不是只要一查用户就把账户查出来。延迟加载
    在查询账户时,账户的所属用户信息应该是随着账户查询时一起查询用户出来。立即加载

    什么是延迟加载
    在真正使用数据时才发起查询,不用的时候不查询。按需加载(懒加载)
    什么是立即加载
    不管用不用,只要一调用方法,马上发起查询。

    在对应的四种表关系中:一对多,多对一,一对一,多对多
    一对多,多对多:通常情况下我们都是采用延迟加载。 要查的是一个集合,空间大!
    多对一,一对一:通常情况下我们都是采用立即加载。

    创建项目模块day04_eesy_01lazy  把day03中的day03_eesy_03one2many项目代码拷贝到当前新创建的这个项目中

     一对一时使用 assocation 实现延迟加载

    (这个标签之前是一对一时在result里写user的,下面是之前的代码

        <!-- 定义封装account和user的resultMap -->
        <resultMap id="accountUserMap" type="account">
            <!--主键 属性与列名-->
            <id property="id" column="aid"></id>
            <!--非主键-->
            <result property="uid" column="uid"></result>
            <result property="money" column="money"></result>
            <!-- 一对一的关系映射:配置封装user的内容-->
            <association property="user" column="uid" javaType="user">
                <id property="id" column="id"></id>
                <result column="username" property="username"></result>
                <result column="address" property="address"></result>
                <result column="sex" property="sex"></result>
                <result column="birthday" property="birthday"></result>
            </association>
        </resultMap>
    View Code

    修改IAccountDao映射文件,需要实现延迟加载

    看现在的assocation标签代码!!!

        <!-- 定义封装account和user的resultMap -->
        <resultMap id="accountUserMap" type="account">
            <!--主键 属性与列名-->
            <id property="id" column="id"></id>
            <!--非主键-->
            <result property="uid" column="uid"></result>
            <result property="money" column="money"></result>
            <!-- 一对一的关系映射:配置封装user的内容
            延迟加载加上select属性指定的内容:查询用户唯一标识(在还能传入方法了。。是IUserDao.xml里面的方法sql语句
            column属性必写上:用户根据id查询时,所需要的id是谁有它指出-->
            <association property="user" column="uid" javaType="user" select="com.xxw.dao.IUserDao.findById">
            </association>
        </resultMap>
    <!-- 查询所有账户同时包含用户名和地址信息 -->
    <select id="findAll" resultMap="accountUserMap">
    select * from account
    </select>

    在主配置文件SqlMapConfig.xml中添加标签,开启延迟加载

    <!--开启Mybatis支持延迟加载-->
    <settings>
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

    一对多时使用 Collection 实现延迟加载

    同上改集合标签,增加seclet属性,关联第二层方法

            <collection property="accounts" ofType="account" select="com.xxw.dao.IAccountDao.findAccountByUid"
                        column="id">
            </collection>

    再要在接口中增加这个方法。具体见pdf 跳跳跳,别看了,后面用注解更好!!!!!

    2、Mybatis中的缓存

    什么是缓存
    存在于内存中的临时数据。
    为什么使用缓存
    减少和数据库的交互次数,提高执行效率。
    什么样的数据能使用缓存,什么样的数据不能使用
    适用于缓存:
    经常查询并且不经常改变的。
    数据的正确与否对最终结果影响不大的。
    不适用于缓存:
    经常改变的数据
    数据的正确与否对最终结果影响很大的。
    例如:商品的库存,银行的汇率,股市的牌价。
    Mybatis中的一级缓存和二级缓存

    一级缓存:

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

    !!!!!!!!!有用的!!!!!到时候剪切遍历数据库,有些是重复的。但是我是以集合或数组的方式取数据,也可以吗?
     <select id="findById" resultType="UsEr" parameterType="int" useCache="true"

     select * from user where id = #{uid} 

    </select>

    二级缓存:

    它指的是Mybatis中SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存
    二级缓存的使用步骤:
    第一步:让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)

    <settings>
    <!-- 开启二级缓存的支持 --> <setting name="cacheEnabled" value="true"/> </settings>
    因为 cacheEnabled 的取值默认就为 true,所以这一步可以省略不配置。为 true 代表开启二级缓存;为 false 代表不开启二级缓存

    第二步:让当前的映射文件支持二级缓存(在IUserDao.xml中配置)

    <mapper namespace="com.itheima.dao.IUserDao"> 

    <!-- 开启二级缓存的支持 --> 

    <cache></cache>

    </mapper> 
    第三步:让当前的操作支持二级缓存(在select标签中配置)

    同一级的标签

    编写测试类:见pdf吧

    经过上面的测试,我们发现执行了两次查询,并且在执行第一次查询后,我们关闭了一级缓存,再去执行第二次查询时,我们发现并没有对数据库发出 sql 语句,所以此时的数据就只能是来自于我们所说的二级缓存。

    3、Mybatis中的注解开发

    Mybatis 也可以使用注解开发方式,这样我们就可以减少编写 Mapper 映射 文件.xml了。

    环境搭建

    创建项目day04_eesy_03annotation_mybatis,导入坐标

    * 在mybatis中针对,CRUD一共有四个注解
    * @Select @Insert @Update @Delete

    当有同路径xml文件时,就算没有配置,也会干扰注解形式开发,所以不要写xml的映射文件了

    单表CRUD操作(代理Dao方式)

    public interface IUserDao {
        /**
         * 查询所有用户
         * * 在mybatis中针对,CRUD一共有四个注解
         *
         * @Select @Insert @Update @Delete
         */
        @Select("select * from user")
        List<User> findAll();
    
        /**
         * 插入用户保存
         *
         * @param user
         */
        @Insert("insert into user(username,address,sex,birthday)values(#{username},#{address},#{sex},#{birthday})")
        void saveUser(User user);
    
        /**
         * 更新用户
         *
         * @param user
         */
        @Update("update user set username = #{username},sex = #{sex},birthday = #{birthday},address = #{address} where id = #{id}")
        void updateUser(User user);
    
        /**
         * 删除用户
         *
         * @param id
         */
        @Delete("delete from user where id = #{id}")
        void deleteUser(Integer id);
    
        /**
         * 根据id查找
         * @param id
         * @return
         */
        @Select("select * from user where id = #{id}")
        User findById(Integer id);
    
        /**
         * 模糊查找
         * @param username
         * @return
         */
        @Select("select * from user where username like #{username}")
        List<User> findByName(String username);
    
        /**
         * 聚合函数查总数
         * @return
         */
        @Select("select count(id) from user")
        int findTotal();
    }
    IUserDao接口
    public class AnnotationCRUDTest {
        private InputStream in;
        private SqlSessionFactory factory;
        private SqlSession session;
        private IUserDao userDao;
    
        @Before
        public  void init()throws Exception{
            in = Resources.getResourceAsStream("SqlMapConfig.xml");
            factory = new SqlSessionFactoryBuilder().build(in);
            session = factory.openSession();
            userDao = session.getMapper(IUserDao.class);
        }
        @After
        public  void destroy()throws  Exception{
            session.commit();
            session.close();
            in.close();
        }
    
        /**
         * 测试查询所有
         */
        @Test
        public void testFindAll(){
            //5.执行查询所有方法
            List<User> users = userDao.findAll();
            for(User user : users){
                System.out.println(user);
            }
        }
    
        @Test
        public void testSave(){
            User user = new User();
            user.setUsername("mybatis annotation");
            user.setAddress("北京市昌平区");
            user.setBirthday(new Date());
            userDao.saveUser(user);
        }
    
        @Test
        public void testUpdate(){
            User user = new User();
            user.setId(50);
            user.setUsername("annotation update");
            user.setAddress("北京市海淀区");
            user.setSex("男");
            user.setBirthday(new Date());
            userDao.updateUser(user);
        }
    
        @Test
        public void testDelete(){
            userDao.deleteUser(53);
        }
    
        @Test
        public void testFindById(){
            User user = userDao.findById(50);
            System.out.println(user);
        }
    
        @Test
        public  void testFindByName(){
            List<User> users = userDao.findByName("%mybatis%");//模糊查询
            for(User user : users){
                System.out.println(user);
            }
        }
    
        @Test
        public  void testFindTotal(){
            int total = userDao.findTotal();
            System.out.println(total);
        }
    }
    Test.java

    mybatis注解建立实体类属性和数据库表中列的对应关系

    创建项目day04_eesy_04annoOne2Many  导入上一个工程的代码

    修改如下:dao接口中只留下关于查询的方法即可(这里方便多了,改接口类即可,不用再像之前还得改对应xml文件)

    修改实体类,让表中的字段不能对应实体类中的属性!!!下图

    (之前xml是用别名解决,resultmap里面的标签

    这里是用results注解了!!!!(那之后一对一的asscousion和多对多的collection应该也是在这个result注解里面?不是,换了。。。

    public interface IUserDao {
        /**
         * 查询所有用户
         * * 在mybatis中针对,CRUD一共有四个注解
         *
         * @Select @Insert @Update @Delete
         */
        @Select("select * from user")
        @Results(id = "userMap",value = {
    //      这个results后面的id=usermap是提供该注解的唯一标识,让别的地方可以调用
    //      开始起别名是属性与列名对应   主键是id所以true?
                @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"),
        }
        )
        List<User> findAll();
    
        /**
         * 根据id查找
         * @param id
         * @return
         */
        @Select("select * from user where id = #{id}")
    //    用@resultmap注解引用唯一标识名称就能用
        @ResultMap("userMap")
        User findById(Integer id);
    
        /**
         * 模糊查找
         * @param username
         * @return
         */
        @Select("select * from user where username like #{username}")
        @ResultMap("userMap")
        List<User> findByName(String username);
    
    }
    IUserDao接口

    多表查询操作

    一对一

    之前学的就是在一的实体类建立多的实体类属性,实现它的setget方法,然后<association>标签里写它的映射

    这里不用association了,用@One这个注解实现一对一还顺便选择饿加载模式,用到select+全限定类名对应方法名(后面查用户的方法)和fetchtype选择加载模式

        /**
         * 查询所有账户,并获取每个帐户所对应的用户信息(一对一多表查询)
         * @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"),
                @Result(property = "user",column = "uid",one=@One(select="com.xxw.dao.IUserDao.findById",fetchType= FetchType.EAGER))
        })
        List<Account> findAll();

    彩色部分方法名想好久才想明白,它是后1/2的方法查一的one!!查用户信息的,通过uid查,方法是IUserDao接口的findById方法,实现这个方法是饿加载!!!!!!!难怪我之前第一章没太懂。。。

    一对多

    之前学的就是在一的实体类建立多的集合实体类属性,实现该集合setget方法,然后<collection>标签里写集合的映射

    用户找账户,账户的方法是后1/2所以要写找账户方法的全名!!!!!和他的加载模式(延迟加载)!!!!它还是多,所以是在@many里面写

        /**IAccountDao.java里面的方法
         * 根据用户id查询账户信息
         * @param userId
         * @return
         */
        @Select("select * from account where uid = #{userId}")
        List<Account> findAccountByUid(Integer userId);

    IUserDao接口加上

        @Select("select * from user")
    @Results(id = "userMap",value = {
    // 这个results后面的id=usermap是提供该注解的唯一标识,让别的地方可以调用
    // 开始起别名是属性与列名对应 主键是id所以true?
    @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.xxw.dao.IAccountDao.findAccountByUid", fetchType = FetchType.LAZY))
    }
    )
    List<User> findAll();

    缓存的配置

    不管xml还是注解,一级缓存都是自动开启的。

    在 SqlMapConfig 中开启二级缓存支持

    <!-- 配置二级缓存 -->

    <settings>
    <!-- 开启二级缓存的支持 --> 这其实也是默认的不写也行

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

    </settings>

    持久层接口中使用注解配置二级缓存

    开二级缓存 这个要写!!!!!!

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

    public interface IUserDao { }

     运行日志显示user1并未从数据库获取而是拿的user的 同一工厂的缓存!!!

    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    mybatis4天学习完毕。pdf资料上讲得挺详细的,感觉mybatis的复习只需要复习day4的第三章注解开发就行。mybatis底层就是day1自定义框架讲得挺详细的。

  • 相关阅读:
    Linux网络基础配置
    UVA 116 Unidirectional TSP(dp + 数塔问题)
    修改Hosts文件
    倒排索引
    可以把阿里云上面的一些介绍和视频都看看
    练练脑,继续过Hard题目
    explicit的用法
    auto_ptr的使用和注意
    我写的快排程序
    快速排序、查第k大
  • 原文地址:https://www.cnblogs.com/gezi1007/p/12861155.html
Copyright © 2020-2023  润新知