MyBatis框架安排
4. 第四天:
1. MyBatis的延遲加載
-
引入問題:在一對多中,我們有一個用戶,他有100個賬戶
- 問題1:在查詢用戶的時候,要不要把賬戶一起關聯出來?
- 問題2:在查詢賬戶時,要不要把用戶一起關聯出來?
答
問題1:在查詢用戶時,應該是什麼時候使用它的賬戶,就什麼時候查。
問題2:查詢賬戶時,用戶應該是隨着賬戶一起被查詢出來,這樣才知道賬戶對應着誰。
什麼是延遲加載:在真正使用數據時才發起查詢,不用時不查詢,又稱按需查詢(懶加載)
立即加載:不管用不用數據,只要一調用查詢方法,就立即查詢。
在對應的四種表關係中:一對多,多對一,一對一,多對多中
通常情況下:
一對多、多對多采用的是延遲加載。
一對一、多對一採用的是立即加載。
簡單記憶:右邊多的採用延遲加載,否則採用立即加載。
演示1:賬戶和用戶的關係,一對一(賬戶 | 用戶)
賬戶和用戶關係:一個賬戶只屬於一個用戶(特定時候一對一),但一個用戶可以有多個賬戶(一對多)
需求:查詢賬戶表信息,賬戶所屬的用戶信息不查詢出來(延遲加載)
-
準備好兩個實體類,Account,User
package com.liuzeyu.domin; import java.io.Serializable; public class Account implements Serializable{ private Integer id; private Integer uid; private Double money; private User user; public User getUser() { return user; } public void setUser(User user) { this.user = user; } @Override public String toString() { return "Account{" + "id=" + id + ", uid=" + uid + ", money=" + money + ", 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; } }
package com.liuzeyu.domin; import java.util.Date; import java.util.List; public class User { private Integer id; private String address; private String username; private String sex; private Date birthday; private List<Account> accounts; public List<Account> getAccounts() { return accounts; } public void setAccounts(List<Account> accounts) { this.accounts = accounts; } @Override public String toString() { return "User{" + "id=" + id + ", address='" + address + '\'' + ", username='" + username + '\'' + ", sex='" + sex + '\'' + ", birthday=" + birthday + '}'; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } }
- 兩個映射配置文件IUserDao.xml,IAccountDao.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.liuzeyu.dao.IUserDao"> <!-- 根據id查找一個 --> <select id="findById" resultType="user" parameterType="int"> select * from user where id=#{uid} </select> </mapper>
如果要配置延遲加載,association標籤則不能封裝User對象,如下
<?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.liuzeyu.dao.IAccountDao"> <resultMap id="rstAc" type="account"> <id property="id" column="id"/> <result property="uid" column="uid"/> <result property="money" column="money"/> <!--javaType="user"映射後封裝的結果集 外鍵:uid select :屬性所指的內容就是查詢用戶的唯一標識 column="uid",其中的uid就是select標籤要查詢的那個id ,不可以刪掉 --> <association property="user" column="uid" javaType="user" select="com.liuzeyu.dao.IUserDao.findById"> </association> </resultMap> <!-- 打印user表數據 --> <select id="findAll" resultMap="rstAc"> SELECT * from account </select> </mapper>
- 準備主配置文件
<?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>--> <!--<!–開啓mybatis支持延遲加載–>--> <!--<setting name="lazyLoadingEnabled" value="true"/>--> <!--<!–關閉mybatis支持立即加載,默認true:mybatis < 3.4.1–>--> <!--<setting name="aggressiveLazyLoading" value="false"/>--> <!--</settings>--> <!--自定義爲配置文件取別名--> <typeAliases> <package name="com.liuzeyu.domin"/> </typeAliases> <!-- mysql配置文件 --> <environments default="mysql"> <environment id="mysql"> <!-- JDBC事物--> <transactionManager type="JDBC"></transactionManager> <!-- JDBC連接池 --> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments> <mappers> <package name="com.liuzeyu.dao"></package> </mappers> </configuration>
- 測試函數
public class Test { private InputStream is = null; private IAccountDao accountDao = null; private SqlSession session = null; /** * 初始化 * @throws IOException */ @Before //測試開始前執行 public void init() throws IOException { //1.解析xml配置文件 is = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.構建工廠 SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is); //3.工廠生產SqlSession對象 session = factory.openSession(); //session = factory.openSession(true); //設置事物的自動提交,可以不用//session.commit(); //4.創建代理Dao的對象 accountDao = session.getMapper(IAccountDao.class); } @After //測試結束後執行 public void destory(){ //session.commit(); //7.釋放資源 if( session != null){ session.close(); } if( is != null){ try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } @org.junit.Test public void testSelect() throws IOException { //5.使用代理對象執行方法 List<Account> accounts = accountDao.findAll(); } }
- 測試結果
- 如果在主配置文件中不配置懶加載
- 如果在主配置文件中配置懶加載
由以上日誌信息可知,如果不配置懶加載,就會去根據id查詢用戶表的信息,配置了懶加載,則不會去查詢用戶表。
- 如果在主配置文件中不配置懶加載
演示2:用戶和賬戶的關係,一對多(用戶 | 賬戶)
在演示1的基礎上添加
-
映射配置IUserDao.xml文件添加
<resultMap id="userMap" type="user"> <id property="id" column="id"/> <result property="address" column="address"/> <result property="sex" column="sex"/> <result property="birthday" column="birthday"/> <result property="username" column="username"/> <collection property="accounts" column="id" select="com.liuzeyu.dao.IAccountDao.findByUid"/> </resultMap> <!-- 根據id查找一個 --> <select id="findAll" resultMap="userMap"> select * from user </select>
-
映射配置IAccountDao.xml文件添加
<!-- 打印uid查詢賬戶 --> <select id="findByUid" resultType="account" parameterType="int"> SELECT * from account where uid=#{uid} </select>
-
測試函數
public class UserTest { private InputStream is = null; private IUserDao userDao = null; private SqlSession session = null; /** * 初始化 * @throws IOException */ @Before //測試開始前執行 public void init() throws IOException { //1.解析xml配置文件 is = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.構建工廠 SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is); //3.工廠生產SqlSession對象 session = factory.openSession(); //session = factory.openSession(true); //設置事物的自動提交,可以不用//session.commit(); //4.創建代理Dao的對象 userDao = session.getMapper(IUserDao.class); } @After //測試結束後執行 public void destory(){ //session.commit(); //7.釋放資源 if( session != null){ session.close(); } if( is != null){ try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } @org.junit.Test public void testSelect() throws IOException { //5.使用代理對象執行方法 List<User> users = userDao.findAll(); } }
-
測試結果
- 在主配置文件中不設置懶加載(默認立即加載)
- 在主配置文件中設置懶加載
- 在主配置文件中不設置懶加載(默認立即加載)
2. MyBatis的緩存
-
什麼是緩存?
答:存在於內存當中的臨時數據。 -
爲什麼使用緩存?
答:減少與數據庫直接打交道,提高執行效率。 -
什麼樣的數據適用緩存,什麼樣的數據不適用?
- 適用緩存:
- 不經常改變的數據
- 並且緩存數據和數據庫不同步時最終影響不大
- 不適用緩存:
- 經常改變的數據
- 並且緩存數據和數據庫不同步時最終影響很大,如商品的庫存,銀行的匯率,股市的牌價等等
- 適用緩存:
-
MyBatis的一級緩存:一級緩存SqlSession對象範圍的緩存,當我們執行查詢之後,查詢結果會同時存入SqlSession爲我們提供的一塊區域中,該區域的結構是Map,當我們再次查詢到同樣的數據時mybatis會先從sqlSession中獲取。當調用SqlSession增刪改,commit(),close()時就會清空一級緩存。
示例:- 準備User實體類
package com.liuzeyu.domin; import java.util.Date; import java.util.List; public class User { private Integer id; private String address; private String username; private String sex; private Date birthday; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } }
- 準備映射配置文件
<?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.liuzeyu.dao.IUserDao"> <!-- 根據id查找一個 --> <select id="findById" resultType="user" parameterType="int"> select * from user where id=#{uid} </select> <!-- 根據id查找一個 --> <select id="updateByUser" parameterType="user"> update user set username=#{username} where id=#{id} </select> </mapper>
- dao層接口
public interface IUserDao { //根據id查找一個 public User findById(Integer id); //根據id查找一個 public void updateByUser(User user); }
- 測試函數
public class UserTest { private InputStream is = null; private IUserDao userDao = null; private SqlSession session = null; SqlSessionFactory factory = null; /** * 初始化 * @throws IOException */ @Before //測試開始前執行 public void init() throws IOException { //1.解析xml配置文件 is = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.構建工廠 factory = new SqlSessionFactoryBuilder().build(is); //3.工廠生產SqlSession對象 session = factory.openSession(); //session = factory.openSession(true); //設置事物的自動提交,可以不用//session.commit(); //4.創建代理Dao的對象 userDao = session.getMapper(IUserDao.class); } @After //測試結束後執行 public void destory(){ //session.commit(); //7.釋放資源 if( session != null){ session.close(); } if( is != null){ try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } // 測試一級緩存session.clearCache(); @org.junit.Test public void testSelect() throws IOException { //5.使用代理對象執行方法 User users1 = userDao.findById(41); System.out.println(users1); session.clearCache(); User users2 = userDao.findById(41); System.out.println(users2); System.out.println(users1 == users2); } //測試一級緩存:sqlSession的更新操作 @org.junit.Test public void testUpdate() throws IOException { //5.使用代理對象執行方法 User users1 = userDao.findById(41); System.out.println(users1); users1.setUsername("SqlSession update"); userDao.updateByUser(users1); User users2 = userDao.findById(41); System.out.println(users2); System.out.println(users1 == users2); //false } //測試一級緩存:sqlSession.close(); @org.junit.Test public void testClose() throws IOException { //5.使用代理對象執行方法 User users1 = userDao.findById(41); System.out.println(users1); session.close(); SqlSession session = factory.openSession(); IUserDao userDao = session.getMapper(IUserDao.class); //true userDao.updateByUser(users1); User users2 = userDao.findById(41); System.out.println(users2); System.out.println(users1 == users2); //false } }
留下疑問:爲什麼SqlSession的更新和刪除操作,並沒有清空緩存?
-
Mybatis的二級緩存:它是指Mybatis的SqlSessionFactory對象緩存,在同一個SqlSessionFactory創建的SqlSession對象內共享緩存。
二級緩存的使用步驟:
- 讓MyBatis框架支持二級緩存(在SqlMapConfig.xml中配置)
<settings> <setting name="cacheEnabled" value="true"/> </settings>
- 讓接口配置文件支持二級緩存,在IUserDao.xml中配置
<!--開啓配置文件二級緩存--> <cache/>
- 讓當前操作系統支持二級緩存(在接口配置文件的select 標籤中配置)
<!-- useCache="true" --> <select id="findById" resultType="user" parameterType="int" useCache="true"> select * from user where id=#{uid} </select>
示例:
在一級緩存的基礎項目上,新建測試函數
package com.liuzeyu.test;
import com.liuzeyu.dao.IUserDao;
import com.liuzeyu.domin.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import java.io.IOException;
import java.io.InputStream;
public class UserTest2 {
private InputStream is = null;
SqlSessionFactory factory = null;
/**
* 初始化
* @throws IOException
*/
@Before //測試開始前執行
public void init() throws IOException {
//1.解析xml配置文件
is = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.構建工廠
factory = new SqlSessionFactoryBuilder().build(is);
}
@After //測試結束後執行
public void destory(){
if( is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 測試一級緩存session.clearCache();
@org.junit.Test
public void testSecondCash() throws IOException {
SqlSession session1 = factory.openSession();
IUserDao userDao1 = session1.getMapper(IUserDao.class);
User user1 = userDao1.findById(41);
System.out.println(user1);
session1.close();
SqlSession session2 = factory.openSession();
IUserDao userDao2 = session2.getMapper(IUserDao.class);
User user2 = userDao2.findById(41);
System.out.println(user2);
session2.close();
System.out.println(user1 == user2);
}
}
未配置二級緩存:
配置二級緩存:
可見兩個不同的Sqlsession對象共享二級緩存區域,session1將查詢的數據放到了二級緩存中,第二次查詢就無需重新連接數據庫查詢了。
3. MyBatis註解開發
-
環境搭建
- 準備實體類
package com.liuzeyu.domain; import java.io.Serializable; import java.util.Date; public class User implements Serializable { private Integer id; private String username; private Date birthday; private String sex; private String address; @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", birthday=" + birthday + ", sex='" + sex + '\'' + ", adress='" + address + '\'' + '}'; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getAddress() { return address; } public void setAddress(String adress) { this.address = adress; } }
- 主配置文件
<?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> <package name="com.liuzeyu.domain"/> </typeAliases> <!-- 配置環境 --> <environments default="mysql"> <!-- 配置mysql環境 --> <environment id="mysql"> <!-- 配置事物類型 --> <transactionManager type="JDBC"></transactionManager> <!-- 配置數據庫源(連接池)--> <dataSource type="POOLED"> <!-- 配置連接數據庫的四個基本信息 --> <property name="driver" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </dataSource> </environment> </environments> <!-- 指定映射配置文件的位置,映射配置文件是指每一個獨立的dao接口配置--> <mappers> <!--<mapper class="com.liuzeyu.dao.IUserDao"/>--> <package name="com.liuzeyu.dao"/> </mappers> </configuration>
- dao層接口
public interface IUserDao { @Select("select * from user") public List<User> findAll(); }
- 測試函數
public class AnnotationTest { public static void main(String[] args) throws Exception{ //1.加載配置文件 InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.創建SqlSessiionFactory SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is); //3.創建SqlSession對象 SqlSession sqlSession = factory.openSession(); //4.創建dao接口的代理dao IUserDao userDao = sqlSession.getMapper(IUserDao.class); //5.代理dao執行 List<User> users = userDao.findAll(); //6.遍歷 for (User user : users) { System.out.println(user); } //7.釋放資源 sqlSession.close(); is.close(); } }
- 查詢結果
- 注意事項1:
如果使用註解配置,只要是在resource存在,如下目錄結構的映射文件
無論是否在主配置文件中配置mapper映射文件的class屬性,mybatis都會認爲這是錯誤的,因爲他不認識你是否要用註解開發
注意事項2:
註解開發與映射配置文件的區別,爲什麼可以使用註解開發?
由此配置文件有的,註解也都能提供。
-
單表CRUD操作
- 在1的基礎上操作,爲dao層接口添加如下GRUD操作
public interface IUserDao { @Select("select * from user") public List<User> findAll(); //插入一個用戶 @Select("insert into user(username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address})") public List<User> insertUser(User user); //根據id查找某一用戶 @Select("select * from user where id=#{id}") public User findById(Integer id); // 根據id刪除某一用戶 @Delete("delete from user where id=#{id}") public void deleteById(Integer id); // 根據id更新某一用戶的用戶名 @Update("update user set username=#{username} where id=#{id}") public void Update(User user); // 根據name刪除某一用戶集合 //@Select("select * from user where username like '%${username}%'") 不推薦使用 @Select("select * from user where username like #{username}") public List<User> findByName(User user); }
- 測試函數
public class AnnotationTestCRUD { private InputStream is = null; private SqlSession sqlSession = null; private SqlSessionFactory factory = null; private IUserDao dao = null; @Before public void init() throws IOException { //1.加載配置文件 is = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.創建工廠 factory = new SqlSessionFactoryBuilder().build(is); //3.創建SqlSession對象 sqlSession = factory.openSession(true); //4.創建代理dao對象 dao = sqlSession.getMapper(IUserDao.class); } @After public void destory() throws IOException { if(sqlSession != null){ sqlSession.close(); } if(is != null){ is.close(); } } /** * 插入一個用戶 */ @Test public void testInsert(){ User user = new User(); user.setUsername("JAY"); user.setAddress("莆田"); user.setSex("男"); user.setBirthday(new Date()); dao.insertUser(user); } /** * 刪除一個用戶 */ @Test public void testDelete(){ dao.deleteById(50); } /** * 根據id查找某一用戶 */ @Test public void testFindById(){ User user = dao.findById(41); System.out.println(user); } /** * 更新某一用戶 */ @Test public void testUpdate(){ User user = dao.findById(51); user.setUsername("Jack"); dao.Update(user); } /** * 根據id查找某一用戶 */ @Test public void testFindByNames(){ User user = new User(); //user.setUsername("%王%"); user.setUsername("王"); List<User> users = dao.findByName(user); for (User u : users) { System.out.println(u); } } }
-
解決實體類屬性名和數據庫字段名不一致問題
- 在1的基礎上修改字段名,並生成對應的setXXX,getXXX方法
public class User implements Serializable { private Integer userId; private String userName; private Date userBirthday; private String userSex; private String userAddress; @Override public String toString() { return "User{" + "userId=" + userId + ", userName='" + userName + '\'' + ", userBirthday=" + userBirthday + ", userSex='" + userSex + '\'' + ", userAddress='" + userAddress + '\'' + '}'; } 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 Date getUserBirthday() { return userBirthday; } public void setUserBirthday(Date userBirthday) { this.userBirthday = userBirthday; } public String getUserSex() { return userSex; } public void setUserSex(String userSex) { this.userSex = userSex; } public String getUserAddress() { return userAddress; } public void setUserAddress(String userAddress) { this.userAddress = userAddress; } }
- 刪除不需要的dao方法
public interface IUserDao { @Select("select * from user") public List<User> findAll(); @Select("insert into user(username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address})") public List<User> insertUser(User user); @Select("select * from user where id=#{id}") public User findById(Integer id); }
- 測試findAll方法,可見並沒有被封裝進去
- 解決實體類和數據庫字段對應關係
在dao層函數上添加,與接口配置文件的resultMap標籤作用相同
@Select("select * from user") @Results(id = "userMap",value = { @Result(id = true,property = "userId" ,column = "id"), @Result(property = "userName",column = "username"), @Result(property = "userBirthday",column = "birthday"), @Result(property = "userSex",column = "sex"), @Result(property = "userAddress",column = "address") }) public List<User> findAll();
- 測試findAll
- 如果需要在其它地方引用則個Map,可以使用註解ResultMap的value字段引用即可
//@ResultMap(value = {"userMap"}) 簡寫如下 @ResultMap("userMap") @Select("select * from user where id=#{id}") public User findById(Integer id);
- 測試findById
-
多表查詢操作
-
賬戶和用戶的關係(賬戶 | 用戶,多對一) mybatis稱之爲:一對一的關係
- 在4的基礎上新增Account類
public class Account implements Serializable{ private Integer id; private Integer uid; private Double money; private User user; public User getUser() { return user; } public void setUser(User user) { this.user = user; } @Override public String toString() { return "Account{" + "id=" + id + ", uid=" + uid + ", money=" + money + ", 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; } }
- 新增IAccountDao接口及方法
import java.util.List; public interface IAccountDao { @Select("select * from account") @Results(id = "accountMap",value = { @Result(id = true,property = "id" ,column = "id"), @Result(property = "uid",column = "uid"), @Result(property = "money",column = "money"), @Result(property = "user",column = "uid", //賬戶和用戶對應關係是:一對一,使用@One one = @One(select = "com.liuzeyu.dao.IUserDao.findById",fetchType = FetchType.LAZY)) }) public List<Account> findAll(); }
- 測試方法
public class AnnotationTestAccount { private InputStream is = null; private SqlSession sqlSession = null; private SqlSessionFactory factory = null; private IAccountDao dao = null; @Before public void init() throws IOException { //1.加載配置文件 is = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.創建工廠 factory = new SqlSessionFactoryBuilder().build(is); //3.創建SqlSession對象 sqlSession = factory.openSession(true); //4.創建代理dao對象 dao = sqlSession.getMapper(IAccountDao.class); } @After public void destory() throws IOException { if(sqlSession != null){ sqlSession.close(); } if(is != null){ is.close(); } } /** * 查找所有 */ @Test public void testFindAll(){ List<Account> accounts = dao.findAll(); for (Account account : accounts) { System.out.println(account); } }
- 測試結果
-
用戶和賬戶的關係(用戶 | 賬戶 ,一對多)
- User實體類添加屬性Account集合
private List<Account> accounts; public List<Account> getAccounts() { return accounts; } public void setAccounts(List<Account> accounts) { this.accounts = accounts; }
- 在5.1的基礎上新增dao層IAccount接口方法
userId 屬性值 <!-- 通過uid查詢賬戶--> @Select("select * from account where uid=#{userId}") public Account findByUid(Integer id);
- 修改IUserDao的接口方法
public interface IUserDao { @Select("select * from user") @Results(id = "userMap",value = { @Result(id = true,property = "userId" ,column = "id"), @Result(property = "userName",column = "username"), @Result(property = "userBirthday",column = "birthday"), @Result(property = "userSex",column = "sex"), @Result(property = "userAddress",column = "address"), @Result(property = "accounts",column = "id", many = @Many(select = "com.liuzeyu.dao.IAccountDao.findByUid",fetchType= FetchType.LAZY)) }) public List<User> findAll(); }
- 新增測試方法
public class AnnotationTestCRUD { private InputStream is = null; private SqlSession sqlSession = null; private SqlSessionFactory factory = null; private IUserDao dao = null; @Before public void init() throws IOException { //1.加載配置文件 is = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.創建工廠 factory = new SqlSessionFactoryBuilder().build(is); //3.創建SqlSession對象 sqlSession = factory.openSession(true); //4.創建代理dao對象 dao = sqlSession.getMapper(IUserDao.class); } @After public void destory() throws IOException { if(sqlSession != null){ sqlSession.close(); } if(is != null){ is.close(); } } /** * 查找所有 */ @Test public void testFindAll(){ List<User> users = dao.findAll(); for (User user : users) { System.out.println(user); } } }
- 測試結果
-
-
緩存配置
- 一級緩存默認開啓,共享SqlSession
@Test public void testFindById(){ User user1 = dao.findById(41); //sqlSession.clearCache(); 開啓後 user1 == user2爲false User user2 = dao.findById(41); System.out.println(user1 == user2); //true }
- 二級緩存的配置
- 新增類測試二級緩存
這裏需注意的是必須是同一個工廠對象factory纔可以共享二級緩存。public class AnnotationTestSecondLevel { private InputStream is = null; private SqlSessionFactory factory = null; @Before public void init() throws IOException { //1.加載配置文件 is = Resources.getResourceAsStream("SqlMapConfig.xml"); factory = new SqlSessionFactoryBuilder().build(is); } @After public void destory() throws IOException { if(is != null){ is.close(); } } /** * 測試二級緩存 */ @Test public void testSecondLevel(){ SqlSession sqlSession1 = factory.openSession(true); IUserDao dao1 = sqlSession1.getMapper(IUserDao.class); User user1 = dao1.findById(41); System.out.println(user1); sqlSession1.close(); SqlSession sqlSession2 = factory.openSession(true); IUserDao dao2 = sqlSession2.getMapper(IUserDao.class); User user2 = dao2.findById(41); System.out.println(user2); sqlSession2.close(); } }
- 還未配置二級緩存前,測試結果
- 配置二級緩存
- 主配置文件開啓二級緩存,注意要寫到加載配置文件後
<!--開啓二級緩存--> <settings> <setting name="cacheEnabled" value="true"/> </settings>
- dao層接口
- 重新運行測試函數,此時只打開一次數據庫連接
- 主配置文件開啓二級緩存,注意要寫到加載配置文件後
- 一級緩存默認開啓,共享SqlSession