- 簡介
使用Mybatis開發Dao,通常有兩個方法,即原始Dao開發方法和Mapper接口開發方法。
- 主要概念介紹:
MyBatis中進行Dao開發時候有幾個重要的類,它們是SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession。
SqlSession中封裝了對數據庫的操作,如:查詢、插入、更新、刪除等。通過SqlSessionFactory創建SqlSession,而SqlSessionFactory是通過SqlSessionFactoryBuilder進行創建。
1、SqlSessionFactoryBuilder
SqlSessionFactoryBuilder用於創建SqlSessionFacoty,SqlSessionFacoty一旦創建完成就不需要SqlSessionFactoryBuilder了,因為SqlSession是通過SqlSessionFactory生產,所以可以將SqlSessionFactoryBuilder當成一個工具類使用,最佳使用范圍是方法范圍即方法體內局部變量。
2、SqlSessionFactory
SqlSessionFactory是一個接口,接口中定義了openSession的不同重載方法,SqlSessionFactory的最佳使用范圍是整個應用運行期間,一旦創建后可以重復使用,通常以單例模式管理SqlSessionFactory。
3、SqlSession
SqlSession是一個面向用戶的接口, sqlSession中定義了數據庫操作,默認使用DefaultSqlSession實現類。
SqlSession中提供了很多操作數據庫的方法:如:selectOne(返回單個對象)、selectList(返回單個或多個對象),SqlSession是線程不安全的,在SqlSesion實現類中除了有接口中的方法(操作數據庫的方法)還有數據域屬性,SqlSession最佳應用場合在方法體內,定義成局部變量使用,絕對不能將SqlSession實例的引用放在一個類的靜態字段或實例字段中。
打開一個 SqlSession;使用完畢就要關閉它。通常把這個關閉操作放到 finally 塊中以確保每次都能執行關閉。如下:
1 SqlSession session = sqlSessionFactory.openSession(); 2 try { 3 // do work 4 } finally { 5 session.close(); 6 }
- 原始Dao開發方式
原始Dao開發方法需要程序員編寫Dao接口和Dao實現類。
還是以前文提到的簡單的增刪改查為例,來簡單介紹原始Dao開發方式。
1、映射文件
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 <mapper namespace="user"> 6 <!-- 根據id獲取用戶信息 --> 7 <select id="findUserById" parameterType="int" resultType="user"> 8 select * from user where id = #{id} 9 </select> 10 <!-- 根據username模糊查詢用戶信息 --> 11 <select id="findUserByName" parameterType="java.lang.String" resultType="com.luchao.mybatis.first.po.User"> 12 select * from user where username like '%${value}%' 13 </select> 14 <!-- 添加用戶信息 --> 15 <insert id="insertUser" parameterType="com.luchao.mybatis.first.po.User"> 16 <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer"> 17 select LAST_INSERT_ID() 18 </selectKey> 19 insert into user(username,birthday,sex,address) value (#{username},#{birthday},#{sex},#{address}); 20 </insert> 21 <!-- 根據id刪除用戶信息 --> 22 <delete id="deleteUser" parameterType="int"> 23 delete from user where id=#{id} 24 </delete> 25 <!-- 修改用戶信息 --> 26 <update id="updateUser" parameterType="com.luchao.mybatis.first.po.User"> 27 update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} 28 where id=#{id} 29 </update> 30 </mapper>
2、Dao接口
1 public interface UserDao { 2 //根據ID查詢用戶信息 3 public User findUserById(int id) throws Exception; 4 //添加用戶信息 5 public void insertUser(User user) throws Exception; 6 //刪除用戶信息 7 public void deleteUser(int id) throws Exception; 8 }
3、Dao接口實現類
1 public class UserDaoImpl implements UserDao{ 2 3 // 需要向dao實現類中注入SqlSessionFactory 4 // 這里通過構造方法注入 5 private SqlSessionFactory sqlSessionFactory; 6 7 public UserDaoImpl(SqlSessionFactory sqlSessionFactory) { 8 super(); 9 this.sqlSessionFactory = sqlSessionFactory; 10 } 11 @Override 12 public void deleteUser(int id) throws Exception { 13 SqlSession sqlSession = sqlSessionFactory.openSession(); 14 //執行刪除操作 15 sqlSession.insert("user.deleteUser", id); 16 // 提交事務 17 sqlSession.commit(); 18 // 釋放資源 19 sqlSession.close(); 20 } 21 @Override 22 public User findUserById(int id) throws Exception { 23 SqlSession sqlSession = sqlSessionFactory.openSession();//獲取sqlSession 24 User user = sqlSession.selectOne("user.findUserById", id); 25 sqlSession.close();//關閉資源 26 return user; 27 } 28 @Override 29 public void insertUser(User user) throws Exception { 30 SqlSession sqlSession = sqlSessionFactory.openSession(); 31 //執行插入操作 32 sqlSession.insert("user.insertUser", user); 33 // 提交事務 34 sqlSession.commit(); 35 // 釋放資源 36 sqlSession.close(); 37 } 38 }
4、測試代碼:
1 public class MyBatis_dao_test { 2 private SqlSessionFactory sqlSessionFactory; 3 @Before 4 public void init() throws IOException{ 5 //創建sqlSessionFactory 6 //MyBatis配置文件 7 String resource = "SqlMapConfig.xml"; 8 //得到配置文件流 9 InputStream inputStream = Resources.getResourceAsStream(resource); 10 //創建會話工廠,傳入MyBatis的配置信息 11 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 12 } 13 @Test 14 public void testFindUserById() throws Exception{ 15 //創建UserDao對象 16 UserDao userDao = new UserDaoImpl(sqlSessionFactory); 17 //調用UserDao的方法,根據ID查找user 18 User user = userDao.findUserById(10); 19 //打印客戶信息 20 System.out.println(user); 21 } 22 }
5、原始Dao方法總結:
(1)、dao接口實現類方法中存在大量模板方法,如:通過SqlSessionFactory創建SqlSession,調用SqlSession的數據庫操作方法。
(2)、調用sqlSession的數據庫操作方法需要指定statement的id,這里存在硬編碼。
(3)、調用sqlsession方法時傳入的變量,由於sqlsession方法使用泛型,即使變量類型傳入錯誤,在編譯階段也不報錯,不利於程序員開發。
- Mapper動態代理方式
1、實現原理
Mapper接口開發方法只需要程序員編寫Mapper接口(相當於Dao接口),由Mybatis框架根據接口定義創建接口的動態代理對象,代理對象的方法體同上邊Dao接口實現類方法。這樣通過動態代理就實現了將模板方法進行封裝,只需要實現具體的實現即可。
Mapper接口開發需要遵循以下規范:
(1)、 Mapper.xml文件中的namespace與mapper接口的類路徑相同。
(2)、 Mapper接口方法名和Mapper.xml中定義的每個statement的id相同 。
(3)、 Mapper接口方法的輸入參數類型和mapper.xml中定義的每個sql 的parameterType的類型相同。
(4)、 Mapper接口方法的輸出參數類型和mapper.xml中定義的每個sql的resultType的類型相同。
2、Mapper.xml(映射文件)
映射文件與原始Dao開發的映射文件相似,只需要將namespace定於為mapper接口全路徑。
<?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.luchao.mybatis.first.mapper.UserMapper"> <!-- 根據id獲取用戶信息 --> <select id="findUserById" parameterType="int" resultType="user"> select * from user where id = #{id} </select> <!-- 根據username模糊查詢用戶信息 --> <select id="findUserByName" parameterType="java.lang.String" resultType="com.luchao.mybatis.first.po.User"> select * from user where username like '%${value}%' </select> <!-- 添加用戶信息 --> <insert id="insertUser" parameterType="com.luchao.mybatis.first.po.User"> <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer"> select LAST_INSERT_ID() </selectKey> insert into user(username,birthday,sex,address) value (#{username},#{birthday},#{sex},#{address}); </insert> <!-- 根據id刪除用戶信息 --> <delete id="deleteUser" parameterType="int"> delete from user where id=#{id} </delete> <!-- 修改用戶信息 --> <update id="updateUser" parameterType="com.luchao.mybatis.first.po.User"> update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id} </update> </mapper>
3、Mapper.java(接口文件)
1 public interface UserMapper { 2 //根據ID查詢用戶信息 3 public User findUserById(int id) throws Exception; 4 //添加用戶信息 5 public void insertUser(User user) throws Exception; 6 //刪除用戶信息 7 public void deleteUser(int id) throws Exception; 8 //更新用戶信息 9 public void updateUser(User user) throws Exception; 10 //根據用戶名模糊查找 11 public List<User> findUserByName(String user) throws Exception; 12 }
接口定義有如下特點:
(1)、 Mapper接口方法名和Mapper.xml中定義的statement的id相同。
(2)、 Mapper接口方法的輸入參數類型和mapper.xml中定義的statement的parameterType的類型相同。
(3)、 Mapper接口方法的輸出參數類型和mapper.xml中定義的statement的resultType的類型相同。
4、加載UserMapper.xml文件
在SqlMapConfig.xml文件中加載UserMapper.xml,如下:
1 <mappers> 2 <mapper resource="mapper/UserMapper.xml"/> 3 </mappers>
5、測試代碼:
1 public class MyBatis_mapper_test { 2 private SqlSessionFactory sqlSessionFactory; 3 @Before 4 public void init() throws IOException{ 5 //創建sqlSessionFactory 6 //MyBatis配置文件 7 String resource = "SqlMapConfig.xml"; 8 //得到配置文件流 9 InputStream inputStream = Resources.getResourceAsStream(resource); 10 //創建會話工廠,傳入MyBatis的配置信息 11 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 12 } 13 @Test 14 public void testFindUserById() throws Exception{ 15 //獲取sqlSession對象 16 SqlSession sqlSession = sqlSessionFactory.openSession(); 17 //創建UserMapper對象,MyBatis自動生成mapper代理 18 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 19 //調用userMapper的方法 20 User user = userMapper.findUserById(10); 21 //關閉資源 22 sqlSession.close(); 23 //打印客戶信息 24 System.out.println(user); 25 } 26 }
5、Mapper動態代理總結:
(1)、動態代理對象調用sqlSession.selectOne()和sqlSession.selectList()是根據mapper接口方法的返回值決定,如果返回list則調用selectList方法,如果返回單個對象則調用selectOne方法。
(2)、使用mapper代理方法時,輸入參數可以使用pojo包裝對象或map對象,保證dao的通用性。在系統中,dao層的代碼是被業務層公用的。即使mapper接口只有一個參數,可以使用包裝類型的pojo滿足不同的業務方法的需求。
注意:持久層方法的參數可以包裝類型、map等,service方法中建議不要使用包裝類型(不利於業務層的可擴展)。
mybatis開發dao的方法有兩種:原始Dao開發和Mapper動態代理開發,這兩種各有優點。原始Dao開發:程序員要寫Dao和Dao實現,需要些較多的代碼,但是比較好理解。Mapper動態代理:程序員只需要寫Mapper接口,然后按照規范進行配置,MyBatis就會自動實現類似Dao實現,減少模板方法。mybatis官方推薦使用mapper代理方法開發mapper接口,程序員不用編寫mapper接口實現類,使用mapper代理方法時,輸入參數可以使用pojo包裝對象或map對象,保證dao的通用性。