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自定义框架讲得挺详细的。

原文地址:https://www.cnblogs.com/gezi1007/p/12861155.html