1、Mybatis中的延遲加載
問題:在一對多中,當我們有一個用戶,它有100個賬戶。
在查詢用戶的時候,要不要把關聯的賬戶查出來?
在查詢賬戶的時候,要不要把關聯的用戶查出來?
在查詢用戶時,用戶下的賬戶信息應該是,什麼時候使用,什麼時候查詢的。
在查詢賬戶時,賬戶的所屬用戶信息應該是隨着賬戶查詢時一起查詢出來。
什麼是延遲加載
在真正使用數據時才發起查詢,不用的時候不查詢。按需加載(懶加載)
什麼是立即加載
不管用不用,只要一調用方法,馬上發起查詢。
在對應的四種表關係中:一對多,多對一,一對一,多對多
一對多,多對多:通常情況下我們都是採用延遲加載。
多對一,一對一:通常情況下我們都是採用立即加載。
1.延遲加載(一對一,一對多)
@Test public void testFindAll(){ List<Account> accounts = accountDao.findAll(); for(Account account : accounts){ System.out.println("--------每個account的信息------------"); System.out.println(account); /** * 執行account.getUser時,才加載用戶信息 */ System.out.println(account.getUser()); } }
@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());
}
}
public class Account implements Serializable { private Integer id; private Integer uid; private Double money; //從表實體應該包含一個主表實體的對象引用 private User user; }
public class User implements Serializable {
private Integer id;
private String username;
private String address;
private String sex;
private Date birthday;
//一對多關係映射:主表實體應該包含從表實體的集合引用
private List<Account> accounts;
}
public interface IAccountDao { /** * 查詢所有賬戶,同時還要獲取到當前賬戶的所屬用戶信息 * @return */ List<Account> findAll(); /** * 根據用戶id查詢賬戶信息 * @param uid * @return */ List<Account> findAccountByUid(Integer uid); }
public interface IUserDao {
/**
* 查詢所有用戶,同時還要獲取到當前賬戶的所屬用戶信息
* @return
*/
List<User> findAll();
/**
* 根據用戶id查詢賬戶信息
* @param uid
* @return
*/
List<User> findById(Integer uid);
}
<?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"> <configuration> <!-- 配置properties--> <properties resource="jdbcConfig.properties"></properties> <!--配置參數--> <settings> <!--開啓Mybatis支持延遲加載--> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"></setting> </settings> <!--使用typeAliases配置別名,它只能配置domain中類的別名 --> <typeAliases> <package name="com.itheima.domain"></package> </typeAliases> <!--配置環境--> <environments default="mysql"> <!-- 配置mysql的環境--> <environment id="mysql"> <!-- 配置事務 --> <transactionManager type="JDBC"></transactionManager> <!--配置連接池--> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"></property> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </dataSource> </environment> </environments> <!-- 配置映射文件的位置 --> <mappers> <package name="com.itheima.dao"></package> </mappers> </configuration>
Account.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="com.itheima.dao.IAccountDao"> <!-- 定義封裝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屬性指定的內容:查詢用戶的唯一標識: column屬性指定的內容:用戶根據id查詢時,所需要的參數的值 --> <association property="user" column="uid" javaType="user" select="com.itheima.dao.IUserDao.findById"></association> </resultMap> <!-- 查詢所有 --> <select id="findAll" resultMap="accountUserMap"> select * from account </select> <!-- 根據用戶id查詢賬戶列表 --> <select id="findAccountByUid" resultType="account"> select * from account where uid = #{uid} </select> </mapper>
User.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="com.itheima.dao.IUserDao"> <!-- 定義User的resultMap--> <resultMap id="userAccountMap" type="user"> <id property="id" column="id"></id> <result property="username" column="username"></result> <result property="address" column="address"></result> <result property="sex" column="sex"></result> <result property="birthday" column="birthday"></result> <!-- 配置user對象中accounts集合的映射 --> <collection property="accounts" ofType="account" select="com.itheima.dao.IAccountDao.findAccountByUid" column="id"></collection> </resultMap> <!-- 查詢所有 --> <select id="findAll" resultMap="userAccountMap"> select * from user </select> <!-- 根據id查詢用戶 --> <select id="findById" parameterType="INT" resultType="user"> select * from user where id = #{uid} </select> </mapper>
2、Mybatis中的緩存
什麼是緩存
存在於內存中的臨時數據。
爲什麼使用緩存
減少和數據庫的交互次數,提高執行效率。
什麼樣的數據能使用緩存,什麼樣的數據不能使用
適用於緩存:
經常查詢並且不經常改變的。
數據的正確與否對最終結果影響不大的。
不適用於緩存:
經常改變的數據
數據的正確與否對最終結果影響很大的。
例如:商品的庫存,銀行的匯率,股市的牌價。
Mybatis中的一級緩存和二級緩存
一級緩存:
它指的是Mybatis中SqlSession對象的緩存。
當我們執行查詢之後,查詢的結果會同時存入到SqlSession爲我們提供一塊區域中。
該區域的結構是一個Map。當我們再次查詢同樣的數據,mybatis會先去sqlsession中
查詢是否有,有的話直接拿出來用。
當SqlSession對象消失時,mybatis的一級緩存也就消失了。
二級緩存:
它指的是Mybatis中SqlSessionFactory對象的緩存。由同一個SqlSessionFactory對象創建的SqlSession共享其緩存。
二級緩存的使用步驟:
第一步:讓Mybatis框架支持二級緩存(在SqlMapConfig.xml中配置)
第二步:讓當前的映射文件支持二級緩存(在IUserDao.xml中配置)
第三步:讓當前的操作支持二級緩存(在select標籤中配置)
1.一級緩存
/** * 測試一級緩存 */ @Test public void testFirstLevelCache(){ User user1 = userDao.findById(41); System.out.println(user1); // sqlSession.close(); // 再次獲取SqlSession對象 // sqlSession = factory.openSession(); // sqlSession.clearCache();//此方法也可以清空緩存 userDao = sqlSession.getMapper(IUserDao.class); User user2 = userDao.findById(41); System.out.println(user2); System.out.println(user1 == user2); } /** * 測試緩存的同步 */ @Test public void testClearlCache(){ //1.根據id查詢用戶 User user1 = userDao.findById(41); System.out.println(user1); //2.更新用戶信息 user1.setUsername("update user clear cache"); user1.setAddress("北京市海淀區"); userDao.updateUser(user1); //3.再次查詢id爲41的用戶 User user2 = userDao.findById(41); System.out.println(user2); System.out.println(user1 == user2); } }
二級緩存
@Test public void testFirstLevelCache(){ SqlSession sqlSession1 = factory.openSession(); IUserDao dao1 = sqlSession1.getMapper(IUserDao.class); User user1 = dao1.findById(41); System.out.println(user1); sqlSession1.close();//一級緩存消失 SqlSession sqlSession2 = factory.openSession(); IUserDao dao2 = sqlSession2.getMapper(IUserDao.class); User user2 = dao2.findById(41); System.out.println(user2); sqlSession2.close(); System.out.println(user1 == user2); }
<?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"> <configuration> <!-- 配置properties--> <properties resource="jdbcConfig.properties"></properties> <settings> <setting name="cacheEnabled" value="true"/> </settings> <!--使用typeAliases配置別名,它只能配置domain中類的別名 --> <typeAliases> <package name="com.itheima.domain"></package> </typeAliases> <!--配置環境--> <environments default="mysql"> <!-- 配置mysql的環境--> <environment id="mysql"> <!-- 配置事務 --> <transactionManager type="JDBC"></transactionManager> <!--配置連接池--> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"></property> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </dataSource> </environment> </environments> <!-- 配置映射文件的位置 --> <mappers> <package name="com.itheima.dao"></package> </mappers> </configuration>
<?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="com.itheima.dao.IUserDao"> <!--開啓user支持二級緩存--> <cache/> <!-- 查詢所有 --> <select id="findAll" resultType="user"> select * from user </select> <!-- 根據id查詢用戶 --> <select id="findById" parameterType="INT" resultType="user" useCache="true"> select * from user where id = #{uid} </select> <!-- 更新用戶信息--> <update id="updateUser" parameterType="user"> update user set username=#{username},address=#{address} where id=#{id} </update> </mapper>