MyBatis学习笔记第四天、MyBatis延迟加载、MyBatis缓存、MyBatis使用注解开发

Windows下用Docker快速搭建SearXNG私有搜索引擎(附Dify集成配置) 本文详细介绍了在Windows环境下使用Docker快速搭建SearXNG私有搜索引擎的完整流程,包括环境准备、容器化部署、安全配置优化以及与Dify平台的深度集成方法。通过分步指导和实用配置示例,帮助开发者构建兼具隐私保护和AI增强能力的本地化搜索解决方案,特别适合需要定制化搜索服务的应用场景。 阅读详情

1. MyBatis中的延迟加载

1.1 立即加载和延迟加载

在我们前面的学习中,我们举了用户和账户的例子,如果有一个用户,它有1000个账户甚至更多,那么在我们查询的时候问题就来了,

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

对于我们来说,当然是需要的时候再去查询,不需要就不查询。例如问题1,当查询用户的时候,我只关心用户的基本信息,不关心用户的账户信息,那么这时就不应该把用户的账户信息也查出来。如果每次查询用户的时候都同时把用户的账户信息也查出来,这样会占用很多额外的开销,账户信息在需要的时候去查询即可。但是对于问题2就不一样了,因为每个账户只有一个用户,在查询账户的时候当然希望吧账户所属的用户信息也查询出来。
立即加载
不管用不用,只要一调用方法,马上发起查询。
延迟加载
就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载。

  • 好处: 先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。
  • 坏处:因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。

在对应的四种表关系(一对多,多对一,一对一,多对多)中建议使用的加载方式

表关系加载方式
一对多,多对多通常情况下我们都是采用延迟加载(懒加载)
多对一,一对一通常情况下我们都是采用立即加载

1.2 延迟加载的使用

首先在当前的工程下新建一个Module命名为 day04_01lazy,然后把之前创建的Module day03_03mybatis_one2many里src下的文件全部拷贝到 day04_01lazy 的src里,不要忘记修改pom.xml文件,然后把无关的文件都删除掉只保留用于测试延迟加载的文件,Module的结构如下:
在这里插入图片描述

在这里插入图片描述

  • 修改MyBatis的主配置文件,在settings中添加 lazyLoadingEnabled 和 aggressiveLazyLoading 的配置,主配置文件SqlMapperConfig.xml内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--上面是mybatis的主配置文件的约束-->

<!--"configuration的配置必须按照这个顺序否则报错:
(properties,settings,typeAliases,typeHandlers,objectFactory,objectWrapperFactory,
reflectorFactory,plugins,environments,databaseIdProvider,mappers)"-->
<configuration>
    <!-- 配置properties-->
    <properties resource="jdbcConfig.properties"></properties>

    <!--配置参数-->
    <settings>
        <!--开启MyBatis支持延迟加载的全局开关-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--开启时,任一方法的调用都会加载该对象的所有延迟加载属性。 否则,每个延迟加载属性会按需加载-->
        <setting name="aggressiveLazyLoading" value="true"/>
    </settings>

    <!--使用typeAliases配置别名,它只能配置domain中类的别名-->
    <typeAliases>
        <!--typeAlias用于配置别名。type属性指定的是实体类的全限定类名。alias属性指定别名,当指定了别名就不在区分大小写-->
        <!--<typeAlias type="com.itheima.domain.User" alias="user"></typeAlias>-->
        <!--用于指定要配置别名的包,当指定之后,该包下的实体类都会注册别名,并且类名就是别名,不在区分大小写-->
        <package name="com.itheima.domain"/>
    </typeAliases>
    <!--配置环境-->
    <environments default="mysql">
        <!--配置mysql的环境-->
        <environment id="mysql">
            <!--配置事务-->
            <transactionManager type="JDBC"></transactionManager>
            <!--配置连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <!--配置映射文件的位置-->
    <mappers>
        <mapper resource="com/itheima/dao/IUserDao.xml"></mapper>
        <mapper resource="com/itheima/dao/IAccountDao.xml"></mapper>
    </mappers>
</configuration>

注意:configuration 配置标签的顺序
properties,settings,typeAliases,typeHandlers,objectFactory,objectWrapperFactory,reflectorFactory,plugins,environments,databaseIdProvider,mappers。必须按照这个顺序否则报错,下图展示的官方文档中所要求的的顺序。
在这里插入图片描述

MyBatis的官方文档

1.3.1 一对一的延迟加载

一对一的延时加载,我们通过查询账户信息,同时查询出账户所属的用户信息来学习。

  • IAccountDao.java 接口里的方法只保留 findAll 和 findAccountByUid 方法。
public interface IAccountDao {
    /**
     * 查询所有的账户,同时还要获取当前账户的所属用户信息
     * @return
     */
    List<Account> findAll();
    /**
     * 根据用户的id查询账户
     * @param uid 用户id
     * @return
     */
    List<Account> findAccountByUid(Integer uid);
}
  • IUserDao.java 接口里的方法只保留 findAll 和 findById 方法。
public interface IUserDao {
    /**
     * 查询所有用户的操作,同时获取到用户下所有账户的信息
     * @return
     */
    List<User> findAll();
    /**
     * 根据id查询用户
     * @param userId 用户id
     * @return
     */
    User findById(Integer userId);
}
  • IAccountDao 的修改映射文件IAccountDao.xml,注意 association 标签里的 select 属性表示延迟加载时要调用的方法,这里的colum的值就是其参数
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--上面的是mapper的约束,不要写错了-->

<!--namespace表示Dao的接口-->
<mapper namespace="com.itheima.dao.IAccountDao">
    <!-- 定义封装account和user的resultMap -->
    <resultMap id="accountUser" type="account">
        <id property="id" column="id"/>
        <result property="uid" column="uid"/>
        <result property="money" column="money"/>
        <!-- 一对一的关系映射:配置封装user的内容
             select属性指定的内容:查询用户的唯一标识
             column属性指定的内容:用户根据id查询时,所需要的参数的值
         -->
        <association property="user" column="uid" javaType="user"
                     select="com.itheima.dao.IUserDao.findById">
        </association>
    </resultMap>
    <!--查询所有-->
    <select id="findAll" resultMap="accountUser">
        select * from account;
    </select>
    <!--根据用户id查询账户列表-->
    <select id="findAccountByUid" parameterType="integer" resultType="account">
        select * from account where uid =#{uid};
    </select>
</mapper>
  • 下面修改测试类 AccountTest.java
public class AccountTest {
    private InputStream in = null;
    private SqlSession session = null;
    private IAccountDao dao = null;
    /**
     * 初始化Mybatis
     * @throws Exception
     */
    @Before //用于在测试方法之前执行
    public void init() throws Exception {
        //1.读取配置文件,生成字节输入流
        in = Resources.getResourceAsStream("SqlMapperConfig.xml");
        //2.获取SqlSessionFactor对象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sessionFactory = builder.build(in);
        //3.获取SqlSession对象
        session = sessionFactory.openSession();
//        session = sessionFactory.openSession(true); //这样就不用事务的手动提交了,就会自动提交
        //4.获取Dao的代理对象
        dao = session.getMapper(IAccountDao.class);
    }
    /**
     * 释放资源
     * @throws Exception
     */
    @After //用于在测试方法之后执行
    public void destroy() throws Exception {
        //提交事务
        session.commit();
        if (in != null)
            in.close();
        if (session != null)
            session.close();
    }
    /**
     * 查询所有的测试
     */
    @Test
    public void testFindAll() {
        try {
            //5.查询所有方法
            List<Account> accounts = dao.findAll();
            for (Account account : accounts) {
                System.out.println(account);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • 我们运行测试方法 testFindAll 之后控制台输出如下:
    在这里插入图片描述
    共执行了3次SQl,程序同时把账户和用户信息都查出来了,这是为什么呢?,这是因为我们 执行 System.out.println(account); 这一句代码,这会去执行 account.toString 方法,代码如下,然后在去执行 user.toString 方法,因为我们用到了user的数据所以触发去查询账户的所属用户信息。
@Override
public String toString() {
	return "Account{" +
	        "id=" + id +
	        ", uid=" + uid +
	        ", money=" + money +
	        ", user=" + user +
	        '}';
}
  • 通过上面的分析,可知当我们在测试方法中吧输入注释掉,这是在执行测试方法。
@Test
public void testFindAll() {
    try {
        //5.查询所有方法
        List<Account> accounts = dao.findAll();
        for (Account account : accounts) {
            // System.out.println(account);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

控制台输出如下,从图中可以看出只执行了一句SQL,说明数据延时加载了。
在这里插入图片描述

1.3.2 一对多的延迟加载

一对多的延迟加载,我们通过查询用户信息同时查询用户的账户信息来学习。

  • 上面我们已经修改过了MyBatis的主配置文件,就不用修改了,下面修改 IUserDao 的 映射配置文件 IUserDao.xml,把 collection 标签里的内容删除掉,然后添加属性 select 其值为 延迟加载时要调用的方法,column 的值就是其参数。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--上面的是mapper的约束,不要写错了-->
<!--namespace表示Dao的接口-->
<mapper namespace="com.itheima.dao.IUserDao">
    <!-- 定义user的resultMap-->
    <resultMap id="userAccountMap" type="User">
        <id property="id" column="id"/>
        <result property="username" column="username"/>
        <result property="address" column="address"/>
        <result property="sex" column="sex"/>
        <result property="birthday" column="birthday"/>
        <!-- 配置user对象中accounts的集合映射 -->
        <collection property="accounts" ofType="account"
                    select="com.itheima.dao.IAccountDao.findAccountByUid"
                    column="id"></collection> <!--这个id是用户的id,因为是用用户的id去查询-->
    </resultMap>
    <select id="findAll" resultMap="userAccountMap" resultType="user">
        select * from user;
    </select>
    <!--根据id查询一个用户-->
    <select id="findById" parameterType="Integer" resultType="User">
        select * from user where id=#{uid};
    </select>
</mapper>
  • 修改测试类 UserTest.java
public class UserTest {
    private InputStream in = null;
    private SqlSession session = null;
    private IUserDao dao = null;
    /**
     * 初始化Mybatis
     * @throws Exception
     */
    @Before //用于在测试方法之前执行
    public void init() throws Exception {
        //1.读取配置文件,生成字节输入流
        in = Resources.getResourceAsStream("SqlMapperConfig.xml");
        //2.获取SqlSessionFactor对象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sessionFactory = builder.build(in);
        //3.获取SqlSession对象
        session = sessionFactory.openSession();
        //4.获取Dao的代理对象
        dao = session.getMapper(IUserDao.class);
    }
    /**
     * 释放资源
     * @throws Exception
     */
    @After //用于在测试方法之后执行
    public void destroy() throws Exception {
        //提交事务
        session.commit();
        if (in != null)
            in.close();
        if (session != null)
            session.close();
    }
    /**
     * 查询所有的测试
     */
    @Test
    public void testFindAll() {
        try {
            //5.查询所有方法
            List<User> users = dao.findAll();
            for (User user : users) {
               System.out.println(user);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • 运行测试方法 testFindAll 你会发现程序把用户查询出来了而且还把账户的信息查询出来了,为什么了这个原因和上面测试一对一延时加载时的原因一样。其实已经实现了延时加载。

2. MyBatis中的缓存

  • 什么是缓存
    • 存到内存中的临时数据。
  • 为什么要使用缓存
    • 为了减少和数据库的交互次数,减少io操作,提高执行效率
      -2.3 什么样的数据能使用缓存,什么样的数据不能使用缓存
    • 在使用缓存时,自然会遇到数据不同步的问题,这就涉及到什么样的数据适合使用缓存,什么样的数据不适合使用缓存。
适用于使用缓存的数据不适用缓存的数据
经常查询并且不经常改变的经常改变的数据
数据的正确与否对最终的结果影响不大的数据的正确与否对最终的结果影响很大的数据
例如:商品的库存例如:银行的汇率,股市的股价

像大多数的持久化框架一样, Mybatis 也提供了缓存策略,通过缓存策略来减少数据库的查询次数, 从而提高性能。
Mybatis 中缓存分为一级缓存,二级缓存。
在这里插入图片描述

2.4 MyBatis中的一级缓存和二级缓存

首先在当前的工程下新建一个Module命名为 day04_02cache,然后把之前创建的Module day03_03mybatis_one2many里src下的文件全部拷贝到 day04_02cache的src里,不要忘记修改pom.xml文件然后把无关的文件都删除掉只保留用于测试缓存的文件,Module的结构如下:
在这里插入图片描述

2.4.1 一级缓存

MyBatis的一级缓存,它指的是MyBatis中SqlSession对象的缓存。当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供一块区域中。该区域的结构是一个Map。当我再次查询同样的数据,mybatis会先去SqlSession中查询是否有,有的话就直接读取。当SqlSession对象消失时,mybatis的一级缓存也就消失了。一级缓存是 SqlSession 级别的缓存,只要 SqlSession 没有 flush 或 close,它就存在。
一级缓存是SqlSession范围的缓存,当调用SqlSession的修改、添加、删除、commit()、close()等方法时,就会清空一级缓存。

  • 修改MyBatis的主配置文件 SqlMapperConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--上面是mybatis的主配置文件的约束-->
<configuration>
    <properties resource="jdbcConfig.properties"></properties>
    <!--全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。-->
    <!--<settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>-->
    <!--使用typeAliases配置别名,它只能配置domain中类的别名-->
    <typeAliases>
        <!--typeAlias用于配置别名。type属性指定的是实体类的全限定类名。alias属性指定别名,当指定了别名就不在区分大小写-->
        <!--<typeAlias type="com.itheima.domain.User" alias="user"></typeAlias>-->
        <!--用于指定要配置别名的包,当指定之后,该包下的实体类都会注册别名,并且类名就是别名,不在区分大小写-->
        <package name="com.itheima.domain"/>
    </typeAliases>
    <!--配置环境-->
    <environments default="mysql">
        <!--配置mysql的环境-->
        <environment id="mysql">
            <!--配置事务-->
            <transactionManager type="JDBC"></transactionManager>
            <!--配置连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <!--配置映射文件的位置-->
    <mappers>
        <mapper resource="com/itheima/dao/IUserDao.xml"></mapper>
    </mappers>
</configuration>
  • 修改IUserDao.java把无关的方法删掉,只保留 findById 和 updateUser 两个方法
public interface IUserDao {
    /**
     * 根据id查询用户
     * @param userId 用户id
     * @return
     */
    User findById(Integer userId);
    /**
     * 更新用户信息
     * @param user 用户
     */
    void updateUser(User user);
}
  • 修改IUserDao的映射配置文件 IUserDao.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--上面的是mapper的约束,不要写错了-->
<!--namespace表示Dao的接口-->
<mapper namespace="com.itheima.dao.IUserDao">
    <!--开启user支持二级缓存-->
    <!--<cache/>-->
    <!--根据id查询一个用户-->
    <select id="findById" parameterType="Integer" resultType="User">
        select * from user where id=#{uid};
    </select>
    <!--更新用户信息-->
    <update id="updateUser" parameterType="user">
        update user set username = #{username},sex= #{sex},address= #{address},birthday= #{birthday} where id = #{id};
    </update>
</mapper>
  • 编写测试类 User.java
public class UserTest {
    private InputStream in = null;
    SqlSessionFactory sessionFactory = null;
    private SqlSession session = null;
    private IUserDao dao = null;
    /**
     * 初始化Mybatis
     * @throws Exception
     */
    @Before //用于在测试方法之前执行
    public void init() throws Exception {
        //1.读取配置文件,生成字节输入流
        in = Resources.getResourceAsStream("SqlMapperConfig.xml");
        //2.获取SqlSessionFactor对象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        sessionFactory = builder.build(in);
        //3.获取SqlSession对象
        session = sessionFactory.openSession();
        //4.获取Dao的代理对象
        dao = session.getMapper(IUserDao.class);
    }
    /**
     * 释放资源
     * @throws Exception
     */
    @After //用于在测试方法之后执行
    public void destroy() throws Exception {
        //提交事务
        session.commit();
        if (in != null)
            in.close();
        if (session != null)
            session.close();
    }
    /**
     * 测试一级缓存
     */
    @Test
    public void testFirstLevelCache() {
        User user1 = dao.findById(4);
        System.out.println(user1);
	    //session.close();
	    //再次获取SqlSession对象
	    //session = sessionFactory.openSession();
	    //重新获取dao
	    //dao = session.getMapper(IUserDao.class);
        //session.clearCache();//此方法也可以清空缓存
        User user2 = dao.findById(4);
        System.out.println(user2);
        System.out.println(user1 == user2);
    }
    /**
     * 测试缓存同步
     */
    @Test
    public void testClearCache() {
        //1.先去查询用户
        User user1 = dao.findById(3);
        System.out.println(user1);
        //2.跟新用户信息
        user1.setUsername("update user clear cache");
        user1.setAddress("北京海淀区");
        dao.updateUser(user1);
        //3.再一次查询id为3的用户
        User user2 = dao.findById(3);
        System.out.println(user2);
        System.out.println(user1 == user2);
    }
}
  • 运行测试方法 testFirstLevelCache 控制台输出如下,值查询了一次数据库,并且两个对象的地址相同,其证明了一级缓存的存在。
    在这里插入图片描述
  • 测试方法 testFirstLevelCache 做如下修改
public void testFirstLevelCache() {
        User user1 = dao.findById(4);
        System.out.println(user1);
	    session.close();
	    //再次获取SqlSession对象
	    session = sessionFactory.openSession();
	    //重新获取dao
	    dao = session.getMapper(IUserDao.class);
        //session.clearCache();//此方法也可以清空缓存
        User user2 = dao.findById(4);
        System.out.println(user2);
        System.out.println(user1 == user2);
    }

然后在一次运行 测试方法 testFirstLevelCache 控制台输出如下,执行了两次数据库的查询语句,并行两个对象的地址不相同。证明了当SqlSession关闭之后,一级缓存就会消失。
在这里插入图片描述

  • 测试缓存的同步
    运行测试方法 testClearCache 控制台输出如下,可以发现当执行update操作后,在一次查询用户时是从数据库查询的。
    在这里插入图片描述

2.4.2 二级缓存

它指的是MyBatis中SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。
在这里插入图片描述

2.4.2.1 二级缓存的使用步骤
  • 要想使用MyBatis的二级缓存就必须进行一下配置

    第一步:让MyBatis框架支持二级缓存(在SqlMapConfig.xml中配置)
    
<configuration>
	...
	<settings>
		 <!--全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。-->
	     <setting name="cacheEnabled" value="true"/>
	</settings>
	...
</configuration>
	第二步:让当前的映射文件支持二级缓存(在IUserDao.xml中配置)
<!--namespace表示Dao的接口-->
<mapper namespace="com.itheima.dao.IUserDao">
    <!--让user支持二级缓存-->
    <cache/>
    ...
</mapper>
	第三步:让当前的操作支持二级缓存(在select标签中配置),在select标签中添加 useCache="true"属性
<!--根据id查询一个用户-->
<select id="findById" parameterType="Integer" resultType="User" useCache="true">
    select * from user where id=#{uid};
</select>
  • 编写测试类 SecondLevelCacheTest.java
public class SecondLevelCacheTest {
    private InputStream in = null;
    private SqlSessionFactory sessionFactory = null;
    /**
     * 初始化Mybatis
     * @throws Exception
     */
    @Before //用于在测试方法之前执行
    public void init() throws Exception {
        //1.读取配置文件,生成字节输入流
        in = Resources.getResourceAsStream("SqlMapperConfig.xml");
        //2.获取SqlSessionFactor对象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        sessionFactory = builder.build(in);
    }
    /**
     * 释放资源
     * @throws Exception
     */
    @After //用于在测试方法之后执行
    public void destroy() throws Exception {
        if (in != null)
            in.close();
    }
    /**
     * 测试二级缓存
     */
    @Test
    public void testFirstLevelCache() {
        SqlSession sqlSession1 = sessionFactory.openSession();
        IUserDao dao1 = sqlSession1.getMapper(IUserDao.class);
        User user1 = dao1.findById(4);
        System.out.println(user1);
        sqlSession1.close(); //这里关闭SqlSession是为了让一级缓存消失

        SqlSession sqlSession2 = sessionFactory.openSession();
        IUserDao dao2 = sqlSession2.getMapper(IUserDao.class);
        User user2 = dao2.findById(4);
        System.out.println(user2);
        sqlSession2.close();
        System.out.println(user1 == user2);
    }
}

执行测试方法 testFirstLevelCache 控制台输出如下,经过上面的测试,我们发现执行了两次查询,并且在执行第一次查询后,我们关闭了一级缓存,再去执行第二次查询时,我们发现并没有对数据库发出 sql 语句,所以此时的数据就只能是来自于我们所说的二级缓存。两次执行findById 方法都拿到了数据,但是两个对象的地址不一样,这是因为,二级缓存,储存的数据时序列化的,当我们去向二级缓存拿数据时在反序列化。所以两个对象的地址不一样。因此,当我们在使用二级缓存时,所缓存的类一定要实现 java.io.Serializable 接口,这种就可以使用序列化方式来保存对象。
在这里插入图片描述

3. MyBatis中的注解开发

3.1 环境搭建

在当前段项目下新建一个名为day04_03annotation_mybatis的Maven的Module,然后创建jdbcConfig.properties、log4j.properties、sqlMapperConfig.xml。然后创建domain类User.java和对应的IUserDao.java,和测试类。该Module的结构如下
在这里插入图片描述

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

sqlMapperConfig.xml内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--上面是mybatis的主配置文件的约束-->
<configuration>
    <!--引入外部配置文件-->
    <properties resource="jdbcConfig.properties"/>
    <typeAliases>
        <!--typeAlias用于配置别名。type属性指定的是实体类的全限定类名。alias属性指定别名,当指定了别名就不在区分大小写-->
        <!--<typeAlias type="com.itheima.domain.User" alias="user"></typeAlias>-->
        <!--用于指定要配置别名的包,当指定之后,该包下的实体类都会注册别名,并且类名就是别名,不在区分大小写-->
        <package name="com.itheima.domain"/>
    </typeAliases>
    <!--配置环境-->
    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <!--指定带有注解的dao接口所在位置-->
    <mappers>
    	<!--加载这个包下的所有dao接口-->
        <package name="com.itheima.dao"/>
 		<!--<mapper class="com.itheima.dao.IUserDao"/>-->
    </mappers>
</configuration>

其中IUserDao.java的内容如下

/**
 * 在MyBatis中针对CRUD一共有四个注解
 * @Select @Insert @Update @Delete
 */
public interface IUserDao {
    /**
     * 查询所有的用户
     * @return
     */
    @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},address=#{address},sex=#{sex},birthday=#{birthday}")
    void updateUser(User user);
    /**
     * 根据id删除用户
     * @param id
     */
    @Delete("delete from user where id=#{id}")
    void deleteUser(Integer id);
    /**
     * 根据id查询用户
     * @param userId
     * @return
     */
    @Select("select * from user where id=#{id}")
    User findById(Integer userId);
    /**
     * 根据用户名进行模糊查询
     * @param name
     * @return
     */
    //@Select("select * from user where username like #{username};")
    //这里的value是固定的写法
    @Select("select * from user where username like '%${value}%'")
    List<User> findByName(String name);
    /**
     * 查询用户总数
     * @return
     */
    @Select("select count(*) from user")
    int findTotalUsers();
}

测试类AnnotationCRUDTest.java的内容如下:

public class AnnotationCRUDTest {
    private InputStream in;
    private SqlSessionFactory factory;
    private SqlSession session;
    private IUserDao userDao;
    @Before
    public void init() throws IOException {
        //1.获取字节输入流
        in = Resources.getResourceAsStream("SqlMapperConfig.xml");
        //2.根据字节输入流构建SqlSessionFactory
        factory = new SqlSessionFactoryBuilder().build(in);
        //3.根据SqlSessionFactory生产一个SqlSession
        session = factory.openSession();
        //4.使用SqlSession获取dao的代理对象
        userDao = session.getMapper(IUserDao.class);
    }
    @After
    public void destroy() throws IOException {
        session.commit();
        session.close();
        in.close();
    }
    @Test
    public void testSave() {
        User user = new User();
        user.setUsername("mybatis annotation");
        user.setAddress("北京市昌平区");
        userDao.saveUser(user);
    }
    @Test
    public void testUpdateUser() throws ParseException {
        User user = new User();
        user.setId(8);
        user.setUsername("mybatis annotation");
        user.setAddress("北京市昌平区");
        user.setSex("男");
        // JDK 1.8之前
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = sdf.parse("1994-01-06");

        user.setBirthday(date);
        userDao.saveUser(user);
    }
    @Test
    public void testDeleteUser() {
        userDao.deleteUser(3);
    }
    @Test
    public void testFindById() {
        User user = userDao.findById(4);
        System.out.println(user);
    }
    @Test
    public void testFindByName() {
        //List<User> users = userDao.findByName("%小%");
        //如果dao里的注解 @Select("select * from user where username like '%${value}%'")
        // 在传参的时候就不用加%
        List<User> users = userDao.findByName("小");
        for (User user : users) {
            System.out.println(user);
        }
    }
    @Test
    public void testFindTotal() {
        int userCount = userDao.findTotalUsers();
        System.out.println(userCount);
    }
}
  • 注意:
    当使用注解进行开发时,但是在配置文件目录下同时包含了同一个dao的映射配置文件,此时不管用不用映射配置文件都会在实际运行时报错。 如下图,如果IUserDao.xml不在 resource/com.itheima.dao的这个包里面就不会报错
    在这里插入图片描述

3.2 多表查询操作

在当前的项目下新建一个名为day04_04anno_one2many的Maven的Module,把上一节中名为day04_03annotation_mybatis中src下的文件拷贝到当前Module的src目录下。然后拷贝一下配置文件。目录结构如下:
在这里插入图片描述

3.2.1 实体类属性名和数据库列名关系映射
  • 据库的列名和实体类的属性名不对应的解决办法,修改一下User.java
public class User implements Serializable {
    private Integer userId;
    private String userName;
    private String UserAddress;
    private String userSex;
    private Date userBirthday;
    public Integer getUserId() {
        return userId;
    }
    public void setUserId(Integer userId) {
        this.userId = userId;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getUserAddress() {
        return UserAddress;
    }
    public void setUserAddress(String userAddress) {
        UserAddress = userAddress;
    }
    public String getUserSex() {
        return userSex;
    }
    public void setUserSex(String userSex) {
        this.userSex = userSex;
    }
    public Date getUserBirthday() {
        return userBirthday;
    }
    public void setUserBirthday(Date userBirthday) {
        this.userBirthday = userBirthday;
    }
    @Override
    public String toString() {
        return "User{" +
                "userId=" + userId +
                ", userName='" + userName + '\'' +
                ", UserAddress='" + UserAddress + '\'' +
                ", userSex='" + userSex + '\'' +
                ", userBirthday=" + userBirthday +
                '}';
    }
}

然后修改IUserDao.java

public interface IUserDao {
    /**
     * 查询所有的用户
     * @return
     */
    @Select("select * from user;")
    // 解决数据库的列名和实体类的属性名不对应的办法,这里类似使用映射配置文件中的Results
    //Result id值要用的唯一的
    @Results(id = "userMap", value = {
    		//id默认为false,表示不知主键,设置为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 userId
     * @return
     */
    @Select("select * from user where id=#{id}")
    //这个ResultMap的标准写法,重复使用上面定义的实体类属性和数据库列名的对应关系
    // @ResultMap(value = {"userMap"})
    //因为注解只有一个value属性,"value="可以省略,又因为数组里只有一个元素,所以"{}"这个大括号也可以省略
    @ResultMap("userMap")
    User findById(Integer userId);
    /**
     * 根据用户名进行模糊查询
     * @param name
     * @return
     */
    @Select("select * from user where username like #{username};")
    //这里使用上面定义好的数据库类名和实体类属性名的映射
    @ResultMap("userMap")
    List<User> findByName(String name);
}

测试类AnnotationCRUDTest .java修改如下

public class AnnotationCRUDTest {
    private InputStream in;
    private SqlSessionFactory factory;
    private SqlSession session;
    private IUserDao userDao;

    @Before
    public void init() throws IOException {
        //1.获取字节输入流
        in = Resources.getResourceAsStream("SqlMapperConfig.xml");
        //2.根据字节输入流构建SqlSessionFactory
        factory = new SqlSessionFactoryBuilder().build(in);
        //3.根据SqlSessionFactory生产一个SqlSession
        session = factory.openSession();
        //4.使用SqlSession获取dao的代理对象
        userDao = session.getMapper(IUserDao.class);
    }
    @After
    public void destroy() throws IOException {
        session.commit();
        session.close();
        in.close();
    }
    @Test
    public void testFindAll() {
        List<User> users = userDao.findAll();
        for (User user : users) {
            System.out.println(user);
        }
    }

    @Test
    public void testFindById() {
        User user = userDao.findById(4);
        System.out.println(user);
    }
    @Test
    public void testFindByName() {
        List<User> users = userDao.findByName("%小%");
        for (User user : users) {
            System.out.println(user);
        }
    }
}
3.2.2 多表查询
一对一查询

一对一查询,我们这里使用查询账户信息的时候同时查询账户的所属用户信息来演示一对一的查询,在原来的基础上新建domain类 Account.java

public class Account implements Serializable {
    private Integer id;
    private Integer uid;
    private Double money;
    //多对一(Mybatis中称之为一对一的)的映射,一个账户只能属于一个用户
    private User user;
    public User getUser() {
        return user;
    }
    public void setUser(User user) {
        this.user = user;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public Integer getUid() {
        return uid;
    }
    public void setUid(Integer uid) {
        this.uid = uid;
    }
    public Double getMoney() {
        return money;
    }
    public void setMoney(Double money) {
        this.money = money;
    }
    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", uid=" + uid +
                ", money=" + money +
                '}';
    }
}

然后新建对应的 IAccountDao.java。注意在注解中的One,这里的One表示一对一,select表示要使用的查询方法(一定要写全限定类名),fetchType表示加载方式(延时加载/立即加载),当一对一查询的时候用立即加载,一对多(这时候用Many)的时候用延迟加载

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"),
            @Result(property = "user", column = "uid", //使用 uid 查询 把结果封装到 user 属性里
                    one = @One(select = "com.itheima.dao.IUserDao.findById", fetchType = FetchType.EAGER))
            //这里的One表示一对一,select表示要使用的查询方法(一定要写全限定类名),fetchType表示加载方式(延时加载/立即加载),当一对一查询的时候用立即加载,一对多的时候用延迟加载
    })
    List<Account> findAll();
}

新建一个测试类 AccountTest.java

public class AccountTest {
    private InputStream in;
    private SqlSessionFactory factory;
    private SqlSession session;
    private IAccountDao accountDao;
    @Before
    public void init() throws IOException {
        //1.获取字节输入流
        in = Resources.getResourceAsStream("SqlMapperConfig.xml");
        //2.根据字节输入流构建SqlSessionFactory
        factory = new SqlSessionFactoryBuilder().build(in);
        //3.根据SqlSessionFactory生产一个SqlSession
        session = factory.openSession();
        //4.使用SqlSession获取dao的代理对象
        accountDao = session.getMapper(IAccountDao.class);
    }
    @After
    public void destroy() throws IOException {
        session.commit();
        session.close();
        in.close();
    }

    @Test
    public void testFindAll() {
        List<Account> accounts = accountDao.findAll();
        for (Account account : accounts) {
            System.out.println("------------------------ 每个账户的信息 ------------------------");
            System.out.println(account);
            System.out.println(account.getUser());
        }
    }
}

然后运行测试类中的 testFindAll 方法,数据封装到了user里。

一对多查询

一对多的查询,我们这里使用查询用户信息的时候查询用户所拥有的账户信息。在原来 User.java类的基础上新增 accounts 属性,并且添加其 get 和 set 方法。

public class User implements Serializable {
    ...
    //一对多的关系映射:一个用户对应多个账户
    private List<Account> accounts;
    public List<Account> getAccounts() {
        return accounts;
    }
    public void setAccounts(List<Account> accounts) {
        this.accounts = accounts;
    }
    ...
}

然后在用 IAccountDao.java中新增一个通过用户id查询其所拥有的账户信息的方法。这个方法也用于,在查询用户信息的时候同时查询用户所拥有的账户信息。

public interface IAccountDao {
	...
    /**
     * 根据有户id查询账户
     * @return 用户所拥有的账户信息
     */
    @Select("select * from account where uid=#{id};")
    List<Account> findAccountByUid(Integer uid);
}

在测试类 AccountTest.java 新增对 findAccountByUid 方法的测试方法。这个测试方法就是测试testFindByUid的,不涉及一对多的查询。

public class AccountTest {
	...
    @Test
    public void testFindByUid() {
        List<Account> accounts = accountDao.findAccountByUid(1);
        for (Account account : accounts) {
            System.out.println("------------------------ 每个账户的信息 ------------------------");
            System.out.println(account);
        }
    }
}

下面修改 IUserDao.java里 findAll 方法的注解。因为是一对多查询,所以在注解里使用 Many 而不是 One,这里是一对多查询,所以使用延时加载。

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();
    ...
}

最后修改 对 IUserDao 的测试类 AnnotationCRUDTest.java 中的 testFindAll 方法。

@Test
    public void testFindAll() {
        List<User> users = userDao.findAll();
        for (User user : users) {
            // System.out.println("---------------------------------------- 用户信息 ----------------------------------------");
            // System.out.println(user);
            // System.out.println(user.getAccounts());
        }
    }
  • 注意:
    在使用注解配置查询方法时,配置延时加载不需要再在MyBatis的主配置里配置, 因为我们使用的注解会自动打开延时加载。
    <!--配置参数-->
        <settings>
            <!--开启MyBatis支持延迟加载的全局开关-->
            <setting name="lazyLoadingEnabled" value="true"/>
            <!--开启时,任一方法的调用都会加载该对象的所有延迟加载属性。 否则,每个延迟加载属性会按需加载-->
            <setting name="aggressiveLazyLoading" value="true"/>
        </settings>
    

运行测试方法 testFindAll 控制台输出如下,可以看出只查询了用户信息没有查询账户信息,实现了延时加载。
在这里插入图片描述

4 注解开发使用二级缓存

无论是使用注解开发还是使用xml开发一级缓存都是不用配置的自动就是有的。比如我们修改一下 测试类 AnnotationCRUDTest.java中的 testFindById 方法如下:

    @Test
    public void testFindById() {
        User user = userDao.findById(4);
        System.out.println(user);
        
        User user2 = userDao.findById(4);
        System.out.println(user2);
        System.out.println(user == user2);
    }

运行一下输出如下,只查询了一次user表,并且两个对象是同一个。
在这里插入图片描述
新建一个测试类 SecondLevelCatchTest.java

public class SecondLevelCatchTest {
    private InputStream in;
    private SqlSessionFactory factory;
    @Before
    public void init() throws IOException {
        in = Resources.getResourceAsStream("SqlMapperConfig.xml");
        factory = new SqlSessionFactoryBuilder().build(in);
    }

    @After
    public void destroy() throws IOException {
        in.close();
    }

    @Test
    public void testFindById() {
        SqlSession session = factory.openSession();
        IUserDao userDao = session.getMapper(IUserDao.class);
        User user = userDao.findById(4);
        System.out.println(user);

        session.close();//关闭session去释放缓存。

        SqlSession session1 = factory.openSession();
        IUserDao userDao1 = session1.getMapper(IUserDao.class);

        User user1 = userDao1.findById(4);
        System.out.println(user1);
        session1.close();
    }
}

运行测试方法 testFindById 输出如下,可以看出是查询了两次。
在这里插入图片描述

设置开启二级缓存

设置在MyBatis的主配置文件中添加开启二级缓存的配置。

	...
	<!--设置开启二级缓存-->
    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>
    ...

然后在要使用二缓存的dao接口上添加注解 @CacheNamespace(blocking = true),如:修改一下IUserDao.java

@CacheNamespace(blocking = true) //设置开启二级缓存
public interface IUserDao {
	...
}

然后在运行一下测试类的测试方法 testFindById 输出如下,只查询了一次user表,说明使用了二级缓存。
在这里插入图片描述
参考:

MyBatis

药物吸收仿真软件:Caco-2_(9).Caco-2模型在药物开发中的案例分析 通过以上五个案例,我们可以看到Caco-2模型在药物开发中的重要作用。它不仅能够帮助我们预测药物的肠道吸收情况,还能够用于优化药物配方、评估代谢稳定性、研究药物相互作用以及转运蛋白的影响。这些体外实验和仿真分析的结果为药物的进一步临床研究提供了重要的参考依据,有助于缩短药物开发周期,提高研发效率。 阅读详情

相关推荐

若依(RuoYi)框架从零到部署:Spring Boot+Vue权限系统完整配置指南

在Java企业级应用开发中,Spring Boot作为构建微服务和单体应用的基石,极大地简化了项目初始化和配置流程。其核心原理在于通过自动配置和起步依赖,快速整合数据访问、安全认证、缓存等常用模块,显著提升开发效率。这一技术价值在需要快速构建后台管理系统的场景中尤为突出,例如权限管理、用户角色分配等通用需求。若依(RuoYi)框架正是基于Spring Boot和Vue.js的优秀实践,它封装了RBAC权限模型、代码生成器等高频功能,提供了开箱即用的解决方案。本文聚焦于若依框架的【环境配置】与【项目部署】,通

weixin_33984032的博客 455

SSM学习之路——Mybatis第四天_使用注解

一、使用注解CRUD (1)创建接口类 注解使用方法如下 Mybatis提供了Select,Insert,Update,Delete四个主要注解 package com.itheima.dao; import com.itheima.domain.User; import org.apache.ibatis.annotations.*; import java.util.List; pub...

SixthMagnitude的博客 346

3D-IC测试挑战与Tessent解决方案解析

3D-IC技术通过硅通孔(TSV)实现芯片垂直堆叠,是延续摩尔定律的关键路径。该技术面临三大核心挑战:KGD标准严苛化要求测试覆盖率达99.5%以上,存储器测试需兼容LPDDR/HBM等多种协议,逻辑堆叠需解决TSV互连的电气特性和时序验证问题。Mentor Tessent平台采用混合测试架构,结合压缩扫描测试(ATPG)和内建自测试(BIST)技术,实现100x测试数据压缩比和99.97%的TSV缺陷检出率。这些创新方案在移动SoC和高性能计算芯片中已获验证,测试时间缩短73%,缺陷逃逸率降低77%。随着

weixin_30621711的博客 376

MyBatis中调用SqlSession.commit()和SqlSession.close()对二级缓存的影响

  在学习MyBatis时,我一直对进行什么操作会影响数据放进二级缓存的情况感到非常疑惑。由此,我特地对各个情况进行测试分析。特别是在分析SqlSession的commit()和close()方法对二级缓存的影响时,花了我好多的时间。只追求最终结果的朋友,可以直接拉到最后看我的总结。 Mapper: &lt;?xml version="1.0" encoding="UTF-8" ?&gt;...

Parker的博客 2万+

嵌入式Linux网络调试踩坑记:YT8531/YT8521 PHY驱动移植与设备树配置实战

本文深入解析嵌入式Linux系统中YT8531/YT8521 PHY驱动移植与设备树配置的实战经验。从网络不通的常见现象入手,详细介绍了驱动移植关键点、设备树配置详解及常见问题排查技巧,帮助开发者快速解决RGMII接口调试难题,提升嵌入式网络开发效率。

weixin_42525328的博客 444

11. 使用 HTTP PUT, PATCH 以及 MERGE 请求消费 SAP ABAP OData 服务修改操作的实现及其区别

使用 SAP ABAP SEGW 事物码实现 OData 服务的修改操作时,对于消费端通过 PATCH/MERGE 和 PUT 这三种不同类型的 HTTP 请求触发的场景,我们应该在 UPDATE_ENTITY 方法里用 IF 分支分别进行处理,原因就在于 GET_ENTITY 方法是否在修改处理逻辑的过程中被触发。......

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 2452

记录Mybatis学习过程(完结,未整理版)

1.报错:Caused by: com.mysql.cj.exceptions.InvalidConnectionAttributeException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone. You must configure either ...

qq_43085979的博客 312

MSVS C# Matlab的混合编程系列2 - 构建一个复杂(含多个M文件)的动态库:

本节我们尝试将一个有很多函数和文件的Matlab算法文件集成到C#的项目里面。

山云的专栏 2068

Mybatis的延迟加载,缓存以及注解开发

Mybatis的延迟加载*** 问题: 在一对多或多对多中,多的一方一般在实体类中表现为一个集合。在查询时,集合的大小是没有理论限制的。 有些时候,此集合的数据在查询后根本不会被使用,就会造成内存空间的极大浪费。 所以,这类数据我们可以在不使用的时候不查询,只有当被使用时才真正查询。达到节省空间和性能的目的。 为什么会有延迟加载?(懒加载) 数据在查询时有一部分是不去查询封装的,而是到真正...

初心不改,事在人为 679

《Python入门到精通》函数详解

函数就是一段「封装」起来的「代码」,目的是提高代码的「模块性」和「复用性」。 2、函数的参数 2.1、变量的就近原则 2.2、传递参数 2.3、形参和实参 2.4、位置参数 2.5、缺省参数 2.6、可变类型和不可变类型 2.7、关键字参数 3、匿名函数 4、函数的返回值

wangyuxiang946的博客 1万+

手把手教你学 AI芯片 SOC软件开发专栏简介

在AI芯片(如NPU、GPU加速器)爆发式增长的今天,软件栈开发已成为AI应用落地的核心瓶颈。无论是模型推理加速、低延迟部署,还是能效优化,都依赖于对芯片底层软件的深度掌握。然而,许多开发者困于“只会调用API,不懂驱动实现”的困境,导致性能瓶颈难以突破。本专栏《手把手教你学 AI芯片 SOC软件开发》专为AI工程师、嵌入式开发者及系统架构师打造,从零基础切入,系统拆解AI芯片SOC(System on Chip)的完整软件栈,覆盖Runtime(运行时)

MHD0815的博客 168

Mybatis中的的延迟加载、缓存和注解开发

Mybatis框架的延迟加载,缓存,和增删改查、多对多、一对多。多对一、一对一的配置与注解开发

徐大大的博客 1181

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Mybatis(延迟加载,缓存,注解开发)

1. Mybatis 延迟加载策略 Mybatis 中一对一,一对多,多对多关系的配置可以实现对象的关联查询。实际开发过程中很多时候我们并不需要总是在加载用户信息时就一定要加载他的账户信息。此时就是我们所说的延迟加载。 1.1 概念 延迟加载:就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载. 好处:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。 坏处:因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查

限定私语的博客 1798

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

MyBatis学习总结(四) MyBatis 延迟加载策略MyBatis 一级缓存、二级缓存MyBatis注解开发

延迟加载:就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载。好处:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。坏处:因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。一对一,多对一:通常情况下我们都是采用立即加载。一对多,多对多:通常情况下我们都是采用延迟加载。

long3359的博客 667

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

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

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

m0_56678122的博客 1455

【JAVA学习笔记】Mybatis注解、延迟加载以及缓存

1. mybatis注解 上一章介绍mybatis的使用时,主要介绍的是通过XML方式进行SQL相关配置,其实我们还可以通过注解来减少编写Mapper映射文件,本章就主要讲解相关的注解。 1.1 常用的CRUD注解 @Insert:实现新增 @Update:实现更新 @Delete:实现删除 @Select:实现查询 通过上面的注解,可以替代mapper.xml里面的相关SQL标签,例如通过 @Select("select * from user") public List<User>

lfj3974的专栏 475

MyBatis延迟加载&注解&缓存

目录 延迟加载: 延迟加载一(多)对一,Assoction实现: Collection 实现延迟加载 (一对多,多对多) MyBatis注解开发 使用 Mybatis 注解实现基本CRUD 使用Mybatis注解实现复杂关系映射开发 复杂关系映射的注解说明 延迟加载: 就是需要用到数据的时才会进行加载,不需要用到数据时就不加载数据,延迟加载也叫懒加载 坏处: 因为只有当需要用到数据时才会进行数据库查询,这样在大批量数据查询时,因为查询工作...

weixin_61300833的博客 662

MyBatis_Day3_MyBatis延迟加载、MyBatis缓存机制、PerpetualCache缓存类、MyBatis注解开发

Lazy Loading(延迟加载)是一种优化数据获取的机制在需要用到数据时才进行加载,不需要用到数据时就不加载数据。合理使用 MyBatis 的延迟加载机制,可以根据实际业务需求,有效地优化数据的获取和处理,提升系统的整体性能。优点:减少不必要的数据查询,降低数据库的压力在处理复杂关系时提高系统性能缺点:可能会增加一定的代码复杂性,需要适当配置和处理如果配置不当,可能会导致多次数据库查询,反而降低性能。

zhong_in_furry的博客 1125

Mybatis中的延迟加载、缓存、注解开发

Mybatis中的延迟加载、缓存、注解开发延迟加载概念配置方式例子缓存缓存概念一级缓存(SqlSession中缓存)触发清空一级缓存的情况二级缓存(SqlSessionFactory中缓存)关于二级缓存与一级缓存生命周期一级缓存二级缓存注解开发注意事项在注解中使用二级缓存 延迟加载 概念 1.Mybatis的延迟加载 问题:在一对多中,当我们有一个用户,它有100个账户。 在查询用户的时候,要不要把关联的账户查出来? 在查询账户的时候,要不要把关联的用户查出来? 在查询用户时,用户下的账户信息应该是,什么时

qq_41995106的博客 525

Mybatis学习第四天:Mybatis延迟加载懒加载,一级缓存,二级缓存,注解开发

文章目录Mybatis中的延迟加载一对一进行延迟加载一对多的延迟加载 Mybatis中的延迟加载 一对一进行延迟加载 一对一的情况下一般是采用立即加载,但为了好理解延迟加载在这里就进行一下演示 在之前 账户和用户的表中,我们一个账户只能是归一个用户所有,所以我们采用查询账户的方式来演示延时加载 首先进行准备工作: 实现根据id来查询用户的功能<select id="findById" resultType="com.gegege.domain.User" parameterType="java.l

qq_35499838的博客 294

MyBatis中的延迟加载、缓存、注解开发

文章目录一、MyBatis的延迟加载1、使用 assocation 实现延迟加载2、使用 Collection 实现延迟加载二、MyBatis缓存1、Mybatis中的一级缓存2、Mybatis中的二级缓存三、Mybatis的注解开发1、mybatis 的常用注解说明2、使用 Mybatis 注解实现基本 CRUD 一、MyBatis的延迟加载 延迟加载:就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载。 好处:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因

321

Mybatis的延迟加载、缓存、注解开发

Mybatis中的延迟加载 Q1:在一对多中,当存在一个用户,它有多个账户。 在查询用户时,是否需要把关联的账户查询出来? 在查询账户时,是否需要把关联的用户查询出来? 查询用户时,用户下的账户信息应该是何时使用何时查询的。 在查询账户时,账户的所属用户信息应该是随着账户查询时一起查询出来。 延迟加载 ​ 在真正使用数据时才发起查询,不用的时候不进行查询。按需加载(懒加载) 立即加载...

Mr_wangr的博客 345

【Mybatis】Mybatis的连接池、延迟加载以及缓存

延迟加载 一对多,多对多:通常采用延迟加载 多对一,一对一:通常采用立即加载 一对一的延迟加载 association 一对一的关系映射:配置封装user的内容 select属性指定的内容:查询用户的唯一标识 column属性指定的内容:用户根据id查询时,所需要的参数的值 <resultMap id="accountUserMap" type="account"> &...

像风走过八千里 1749

MyBatis(三):延迟加载,缓存,注解应用

MyBatis 加载策略 什么是延迟加载? 实际开发过程中很多时候并不需要总是在加载用户信息时就一定要加载他的订单信息。此时就是我们所说的延迟加载。 在一对多中,当有一个用户,它有个100个订单;在查询用户时,用户下的订单应该是,什么时候用,什么时候查询;在查询订单时,订单所属的用户信息应该是随着订单一起查询出来。 延迟加载:就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载。 优点:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比

bier_zm的博客 990

(4)Mybatis————JNDI数据源的使用,延迟加载,缓存以及使用注解开发

1,JNDI数据源 2,Mybatis 延迟加载策略 2.1,何为延迟加载? 2.2,使用 assocation 实现延迟加载 2.3,使用 Collection 实现延迟加载 3,Mybatis 缓存 3.1,Mybatis 一级缓存 3.2,Mybatis 二级缓存 4,Mybatis 注解开发 4.1,mybatis 的常用注解说明 4.2,使用 Mybatis 注解实现基本 CRUD 4.3,使用 Collection 实现延迟加载 4.4,Mybatis 中简化编写的 SQL 片段

qq_2533491534的博客 741

Mybatis延迟加载,缓存和注解开发的简单记录

主要是Myabtis延迟加载的简单理解,还有一级二级缓存的概念和使用,以及使用注解方式进行开发的方式方法.

半束海棠的博客 304
上一篇: MyBatis学习笔记第一天、MyBatis入门、自定义MyBatis的实现
下一篇: Spring学习笔记第一天,Spring框架的概述Spring入门案例以及spring中基于xml的IOC配置
Code_Boy_Code
博客等级 码龄9年 650粉丝 28原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值