通过项目逐步深入了解Mybatis二
Mybatis 解決 jdbc 編程的問題
1、 數據庫鏈接創建、釋放頻繁造成系統資源浪費從而影響系統性能,如果使用數據庫鏈接池可解決此問題。
解決:在SqlMapConfig.xml中配置數據鏈接池,使用連接池管理數據庫鏈接。
2、 Sql語句寫在代碼中造成代碼不易維護,實際應用sql變化的可能較大,sql變動需要改變Java代碼。
解決:將Sql語句配置在XXXXmapper.xml文件中與java代碼分離。
3、 向sql語句傳參數麻煩,因為sql語句的where條件不一定,可能多也可能少,占位符需要和參數一一對應。
解決:Mybatis自動將java對象映射至sql語句,通過statement中的parameterType定義輸入參數的類型。
4、 對結果集解析麻煩,sql變化導致解析代碼變化,且解析前需要遍歷,如果能將數據庫記錄封裝成pojo對象解析比較方便。
解決:Mybatis自動將sql執行結果映射至java對象,通過statement中的resultType定義輸出結果的類型。
Mybatis 與 Hibernate 不同
Mybatis和hibernate不同,它不完全是一個ORM框架,因為MyBatis需要程序員自己編寫Sql語句,不過mybatis可以通過XML或注解方式靈活配置要運行的sql語句,并將java對象和sql語句映射生成最終執行的sql,最后將sql執行的結果再映射生成java對象。
Mybatis學習門檻低,簡單易學,程序員直接編寫原生態sql,可嚴格控制sql執行性能,靈活度高,非常適合對關系數據模型要求不高的軟件開發,例如互聯網軟件、企業運營類軟件等,因為這類軟件需求變化頻繁,一但需求變化要求成果輸出迅速。但是靈活的前提是mybatis無法做到數據庫無關性,如果需要實現支持多種數據庫的軟件則需要自定義多套sql映射文件,工作量大。
Hibernate對象/關系映射能力強,數據庫無關性好,對于關系模型要求高的軟件(例如需求固定的定制化軟件)如果用hibernate開發可以節省很多代碼,提高效率。但是Hibernate的學習門檻高,要精通門檻更高,而且怎么設計O/R映射,在性能和對象模型之間如何權衡,以及怎樣用好Hibernate需要具有很強的經驗和能力才行。
總之,按照用戶的需求在有限的資源環境下只要能做出維護性、擴展性良好的軟件架構都是好架構,所以框架只有適合才是最好。
Mybatis 開發 dao
兩種方法
- 原始 dao 開發方法(程序需要編寫 dao 接口和 dao 實現類)(掌握)
- Mybatis 的 mapper 接口(相當于 dao 接口)代理開發方法(掌握)
需求
將下邊的功能實現Dao:
- 根據用戶id查詢一個用戶信息
- 根據用戶名稱模糊查詢用戶信息列表
- 添加用戶信息
Mybatis 配置文件 SqlMapConfig.xml
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 實現類。
執行過程如下:
1)、 加載數據源等配置信息
Environment environment = configuration.getEnvironment();
2)、 創建數據庫鏈接
3)、 創建事務對象
4)、 創建Executor,SqlSession 所有操作都是通過 Executor 完成,mybatis 源碼如下:
if (ExecutorType.BATCH == executorType) {executor = newBatchExecutor(this, transaction);} elseif (ExecutorType.REUSE == executorType) {executor = new ReuseExecutor(this, transaction);} else {executor = new SimpleExecutor(this, transaction);} if (cacheEnabled) {executor = new CachingExecutor(executor, autoCommit);}5)、 SqlSession的實現類即 DefaultSqlSession,此對象中對操作數據庫實質上用的是 Executor
結論:
每個線程都應該有它自己的SqlSession實例。SqlSession的實例不能共享使用,它也是線程不安全的。因此最佳的范圍是請求或方法范圍(定義局部變量使用)。絕對不能將SqlSession實例的引用放在一個類的靜態字段或實例字段中。打開一個SqlSession;使用完畢就要關閉它。通常把這個關閉操作放到 finally 塊中以確保每次都能執行關閉。如下: SqlSession session = sqlSessionFactory.openSession();try {// do work} finally {session.close(); }原始 Dao 開發方法
思路:
需要程序員編寫 Dao 接口和 Dao 實現類;
需要在 Dao 實現類中注入 SqlsessionFactory ,在方法體內通過 SqlsessionFactory 創建 Sqlsession。
Dao接口
public interface UserDao //dao接口,用戶管理 {//根據id查詢用戶信息public User findUserById(int id) throws Exception;//添加用戶信息public void addUser(User user) throws Exception;//刪除用戶信息public void deleteUser(int id) throws Exception; }Dao 實現類
public class UserDaoImpl implements UserDao //dao接口實現類 {//需要在 Dao 實現類中注入 SqlsessionFactory//這里通過構造方法注入private SqlSessionFactory sqlSessionFactory;public UserDaoImpl(SqlSessionFactory sqlSessionFactory){this.sqlSessionFactory = sqlSessionFactory;}@Overridepublic User findUserById(int id) throws Exception{//在方法體內通過 SqlsessionFactory 創建 SqlsessionSqlSession sqlSession = sqlSessionFactory.openSession();User user = sqlSession.selectOne("test.findUserById", id);sqlSession.close();return user;}@Overridepublic void insertUser(User user) throws Exception{//在方法體內通過 SqlsessionFactory 創建 SqlsessionSqlSession sqlSession = sqlSessionFactory.openSession();//執行插入的操作sqlSession.insert("test.insetrUser", user);//提交事務sqlSession.commit();//釋放資源sqlSession.close();}@Overridepublic void deleteUser(int id) throws Exception{//在方法體內通過 SqlsessionFactory 創建 SqlsessionSqlSession sqlSession = sqlSessionFactory.openSession();sqlSession.delete("test.deleteUserById", id);//提交事務sqlSession.commit();sqlSession.close();} }測試
public class UserDaoImplTest {private SqlSessionFactory sqlSessionFactory;//此方法是在 testFindUserById 方法之前執行的@Beforepublic void setup() throws Exception{//創建sqlSessionFactory//Mybatis 配置文件String resource = "SqlMapConfig.xml";//得到配置文件流InputStream inputStream = Resources.getResourceAsStream(resource);//創建會話工廠,傳入Mybatis的配置文件信息sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);}@Testpublic void testFindUserById() throws Exception{//創建UserDao的對象UserDao userDao = new UserDaoImpl(sqlSessionFactory);//調用UserDao方法User user = userDao.findUserById(1);System.out.println(user);} }通過id查詢用戶信息測試結果如下:(其他的可以自己在寫測試代碼,原理類似)
問題
原始Dao開發中存在以下問題:
- Dao方法體存在重復代碼:通過 SqlSessionFactory 創建 SqlSession,調用 SqlSession 的數據庫操作方法
- 調用 sqlSession 的數據庫操作方法需要指定 statement 的i d,這里存在硬編碼,不得于開發維護。
- 調用 sqlSession 的數據庫操作方法時傳入的變量,由于 sqlsession 方法使用泛型,即使變量類型傳入錯誤,在編譯階段也不報錯,不利于程序員開發。
Mybatis 的 mapper 接口
思路
程序員需要編寫 mapper.xml 映射文件
只需要程序員編寫Mapper接口(相當于Dao接口),需遵循一些開發規范,mybatis 可以自動生成 mapper 接口類代理對象。
開發規范:
在 mapper.xml 中 namespace 等于 mapper 接口地址
<mapper namespace="cn.zhisheng.mybatis.mapper.UserMapper"></mapper>在 xxxmapper.java 接口中的方法名要與 xxxMapper.xml 中 statement 的 id 一致。
在 xxxmapper.java 接口中的輸入參數類型要與 xxxMapper.xml 中 statement 的 parameterType 指定的參數類型一致。
在 xxxmapper.java 接口中的返回值類型要與 xxxMapper.xml 中 statement 的 resultType 指定的類型一致。
UserMapper.java
//根據id查詢用戶信息public User findUserById(int id) throws Exception;UserMapper.xml
<select id="findUserById" parameterType="int" resultType="cn.zhisheng.mybatis.po.User">select * from user where id = #{1} </select>
總結:
以上的開發規范主要是對下邊的代碼進行統一的生成:
User user = sqlSession.selectOne("test.findUserById", id); sqlSession.insert("test.insetrUser", user); sqlSession.delete("test.deleteUserById", id); List<User> list = sqlSession.selectList("test.findUserByName", username);測試
測試之前記得在 SqlMapConfig.xml 文件中添加加載映射文件 UserMapper.xml:
<mapper resource="mapper/UserMapper.xml"/>測試代碼:
public class UserMapperTest {private SqlSessionFactory sqlSessionFactory;//此方法是在 testFindUserById 方法之前執行的@Beforepublic void setup() throws Exception{//創建sqlSessionFactory//Mybatis 配置文件String resource = "SqlMapConfig.xml";//得到配置文件流InputStream inputStream = Resources.getResourceAsStream(resource);//創建會話工廠,傳入Mybatis的配置文件信息sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);}@Testpublic void testFindUserById() throws Exception{SqlSession sqlSession = sqlSessionFactory.openSession();//創建usermapper對象,mybatis自動生成代理對象UserMapper userMapper = sqlSession.getMapper(UserMapper.class);//調用UserMapper的方法User user = userMapper.findUserById(1);System.out.println(user);} }通過id查詢用戶信息測試結果如下:(其他的請自己根據上下文寫測試代碼,或者去看我 Github-Mybatis學習筆記 上看我這個項目的全部代碼)
通過姓名查詢用戶信息:
代理對象內部調用 selectOne 或者 selectList
- 如果 mapper 方法返回單個 pojo 對象(非集合對象),代理對象內部通過 selectOne 查詢數據庫
- 如果 mapper 方法返回集合對象,代理對象內部通過 selectList 查詢數據庫
mapper接口方法參數只能有一個是否影響系統開發
mapper 接口方法參數只能有一個,系統是否不利于維護?
系統框架中,dao層的代碼是被業務層公用的。
即使 mapper 接口只有一個參數,可以使用包裝類型的 pojo 滿足不同的業務方法的需求。
注意:持久層方法的參數可以包裝類型、map…. ,service方法中不建議使用包裝類型。(不利于業務層的可擴展性)
SqlMapConfig.xml 文件
Mybatis 的全局配置變量,配置內容和順序如下:
properties(屬性)
settings(全局配置參數)
typeAliases(類型別名)
typeHandlers(類型處理器)
objectFactory(對象工廠)
plugins(插件)
environments(環境集合屬性對象)
environment(環境子屬性對象)
transactionManager(事務管理)
dataSource(數據源)
mappers(映射器)
properties 屬性
需求:將數據庫連接參數單獨配置在 db.properties 中,只需要在 SqlMapConfig.xml 中加載該配置文件 db.properties 的屬性值。在 SqlMapConfig.xml 中就不需要直接對數據庫的連接參數進行硬編碼了。方便以后對參數進行統一的管理,其他的xml文件可以引用該 db.properties 。
db.properties
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mybatis_test?characterEncoding=utf-8 jdbc.username=root jdbc.password=root那么 SqlMapConfig.xml 中的配置變成如下:
<!--加載配置文件--><properties resource="db.properties"></properties><!-- 和spring整合后 environments配置將廢除--><environments default="development"><environment id="development"><!-- 使用jdbc事務管理,事務由 Mybatis 控制--><transactionManager type="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>配置完成后我們測試一下是否能夠和剛才一樣的能夠成功呢?那么我就先在db.properties中把數據庫密碼故意改錯,看是否是正確的?不出意外的話是會報錯的。
注意: MyBatis 將按照下面的順序來加載屬性:
在 properties 元素體內定義的屬性首先被讀取。
然后會讀取 properties 元素中 resource 或 url 加載的屬性,它會覆蓋已讀取的同名屬性。
最后讀取 parameterType 傳遞的屬性,它會覆蓋已讀取的同名屬性。
因此,通過parameterType傳遞的屬性具有最高優先級,resource或 url 加載的屬性次之,最低優先級的是 properties 元素體內定義的屬性。
建議:
- 不要在 properties 元素體內添加任何屬性值,只將屬性值定義在 db.properties 文件之中。
- 在 db.properties 文件之中定義的屬性名要有一定的特殊性。如 xxx.xxx.xxx
settings(全局配置參數)
Mybatis 框架在運行時可以調整一些運行參數
比如:開啟二級緩存、開啟延遲加載。。。
typeAliases(類型別名)
需求:
在mapper.xml中,定義很多的statement,statement需要parameterType指定輸入參數的類型、需要resultType指定輸出結果的映射類型。
如果在指定類型時輸入類型全路徑,不方便進行開發,可以針對parameterType或resultType指定的類型定義一些別名,在mapper.xml中通過別名定義,方便開發。
Mybatis支持的別名:
| _byte | byte |
| _long | long |
| _short | short |
| _int | int |
| _integer | int |
| _double | double |
| _float | float |
| _boolean | boolean |
| string | String |
| byte | Byte |
| long | Long |
| short | Short |
| int | Integer |
| integer | Integer |
| double | Double |
| float | Float |
| boolean | Boolean |
| date | Date |
| decimal | BigDecimal |
| bigdecimal | BigDecimal |
自定義別名:
在 SqlMapConfig.xml 中配置:(設置別名)
<typeAliases><!-- 單個別名定義 --><typeAlias alias="user" type="cn.zhisheng.mybatis.po.User"/><!-- 批量別名定義,掃描整個包下的類,別名為類名(首字母大寫或小寫都可以) --><package name="cn.zhisheng.mybatis.po"/><package name="其它包"/> </typeAliases>在 UserMapper.xml 中引用別名:( resultType 為 user )
<select id="findUserById" parameterType="int" resultType="user">select * from user where id = #{id} </select>測試結果:
typeHandlers(類型處理器)
mybatis中通過typeHandlers完成jdbc類型和java類型的轉換。
通常情況下,mybatis提供的類型處理器滿足日常需要,不需要自定義.
mybatis支持類型處理器:
| BooleanTypeHandler | Boolean,boolean | 任何兼容的布爾值 |
| ByteTypeHandler | Byte,byte | 任何兼容的數字或字節類型 |
| ShortTypeHandler | Short,short | 任何兼容的數字或短整型 |
| IntegerTypeHandler | Integer,int | 任何兼容的數字和整型 |
| LongTypeHandler | Long,long | 任何兼容的數字或長整型 |
| FloatTypeHandler | Float,float | 任何兼容的數字或單精度浮點型 |
| DoubleTypeHandler | Double,double | 任何兼容的數字或雙精度浮點型 |
| BigDecimalTypeHandler | BigDecimal | 任何兼容的數字或十進制小數類型 |
| StringTypeHandler | String | CHAR和VARCHAR類型 |
| ClobTypeHandler | String | CLOB和LONGVARCHAR類型 |
| NStringTypeHandler | String | NVARCHAR和NCHAR類型 |
| NClobTypeHandler | String | NCLOB類型 |
| ByteArrayTypeHandler | byte[] | 任何兼容的字節流類型 |
| BlobTypeHandler | byte[] | BLOB和LONGVARBINARY類型 |
| DateTypeHandler | Date(java.util) | TIMESTAMP類型 |
| DateOnlyTypeHandler | Date(java.util) | DATE類型 |
| TimeOnlyTypeHandler | Date(java.util) | TIME類型 |
| SqlTimestampTypeHandler | Timestamp(java.sql) | TIMESTAMP類型 |
| SqlDateTypeHandler | Date(java.sql) | DATE類型 |
| SqlTimeTypeHandler | Time(java.sql) | TIME類型 |
| ObjectTypeHandler | 任意 | 其他或未指定類型 |
| EnumTypeHandler | Enumeration類型 | VARCHAR-任何兼容的字符串類型,作為代碼存儲(而不是索引)。 |
mappers(映射器)
使用相對于類路徑的資源,如:
使用完全限定路徑
如:使用 mapper 接口類路徑
如:
注意:此種方法要求 mapper 接口名稱和 mapper 映射文件名稱相同,且放在同一個目錄中。
注冊指定包下的所有mapper接口
如:
注意:此種方法要求 mapper 接口名稱和 mapper 映射文件名稱相同,且放在同一個目錄中。
Mapper.xml 映射文件
Mapper.xml映射文件中定義了操作數據庫的sql,每個sql是一個statement,映射文件是mybatis的核心。
輸入映射
通過 parameterType 指定輸入參數的類型,類型可以是簡單類型、hashmap、pojo的包裝類型。
傳遞 pojo 包裝對象 (重點)
開發中通過pojo傳遞查詢條件 ,查詢條件是綜合的查詢條件,不僅包括用戶查詢條件還包括其它的查詢條件(比如將用戶購買商品信息也作為查詢條件),這時可以使用包裝對象傳遞輸入參數。
定義包裝對象
定義包裝對象將查詢條件(pojo)以類組合的方式包裝起來。
UserQueryVo.java
public class UserQueryVo //用戶包裝類型 {//在這里包裝所需要的查詢條件//用戶查詢條件private UserCustom userCustom;public UserCustom getUserCustom(){return userCustom;}public void setUserCustom(UserCustom userCustom){this.userCustom = userCustom;}//還可以包裝其他的查詢條件,比如訂單、商品 }UserCustomer.java
public class UserCustom extends User //用戶的擴展類 {//可以擴展用戶的信息 }UserMapper.xml 文件
<!--用戶信息綜合查詢#{userCustom.sex} :取出pojo包裝對象中的性別值#{userCustom.username} :取出pojo包裝對象中的用戶名稱--><select id="findUserList" parameterType="cn.zhisheng.mybatis.po.UserQueryVo" resultType="cn.zhisheng.mybatis.po.UserCustom">select * from user where user.sex = #{userCustom.sex} and user.username like '%${userCustom.username}%'</select>UserMapper.java
//用戶信息綜合查詢 public List<UserCustom> findUserList(UserQueryVo userQueryVo) throws Exception;測試代碼
//測試用戶信息綜合查詢@Testpublic void testFindUserList() throws Exception{SqlSession sqlSession = sqlSessionFactory.openSession();//創建usermapper對象,mybatis自動生成代理對象UserMapper userMapper = sqlSession.getMapper(UserMapper.class);//創建包裝對象,設置查詢條件UserQueryVo userQueryVo = new UserQueryVo();UserCustom userCustom = new UserCustom();userCustom.setSex("男");userCustom.setUsername("張小明");userQueryVo.setUserCustom(userCustom);//調用UserMapper的方法List<UserCustom> list = userMapper.findUserList(userQueryVo); System.out.println(list);}測試結果
輸出映射
- resultType
- 使用 resultType 進行輸出映射,只有查詢出來的列名和 pojo 中的屬性名一致,該列才可以映射成功。
- 如果查詢出來的列名和 pojo 中的屬性名全部不一致,沒有創建 pojo 對象。
- 只要查詢出來的列名和 pojo 中的屬性有一個一致,就會創建 pojo 對象。
輸出簡單類型
需求:用戶信息綜合查詢列表總數,通過查詢總數和上邊用戶綜合查詢列表才可以實現分頁
實現:
<!--用戶信息綜合查詢總數parameterType:指定輸入的類型和findUserList一樣resultType:輸出結果類型為 int--><select id="findUserCount" parameterType="cn.zhisheng.mybatis.po.UserQueryVo" resultType="int">select count(*) from user where user.sex = #{userCustom.sex} and user.username like '%${userCustom.username}%'</select> //用戶信息綜合查詢總數public int findUserCount(UserQueryVo userQueryVo) throws Exception;//測試用戶信息綜合查詢總數@Testpublic void testFindUserCount() throws Exception{SqlSession sqlSession = sqlSessionFactory.openSession();//創建usermapper對象,mybatis自動生成代理對象UserMapper userMapper = sqlSession.getMapper(UserMapper.class);//創建包裝對象,設置查詢條件UserQueryVo userQueryVo = new UserQueryVo();UserCustom userCustom = new UserCustom();userCustom.setSex("男");userCustom.setUsername("張小明");userQueryVo.setUserCustom(userCustom);//調用UserMapper的方法System.out.println(userMapper.findUserCount(userQueryVo));}注意:查詢出來的結果集只有一行且一列,可以使用簡單類型進行輸出映射。
輸出pojo對象和pojo列表
不管是輸出的pojo單個對象還是一個列表(list中包括pojo),在mapper.xml中resultType指定的類型是一樣的。
在mapper.java指定的方法返回值類型不一樣:
1、輸出單個pojo對象,方法返回值是單個對象類型
//根據id查詢用戶信息public User findUserById(int id) throws Exception;2、輸出pojo對象list,方法返回值是List
//根據用戶名查詢用戶信息public List<User> findUserByUsername(String userName) throws Exception;resultType總結:
輸出pojo對象和輸出pojo列表在sql中定義的resultType是一樣的。
返回單個pojo對象要保證sql查詢出來的結果集為單條,內部使用session.selectOne方法調用,mapper接口使用pojo對象作為方法返回值。
返回pojo列表表示查詢出來的結果集可能為多條,內部使用session.selectList方法,mapper接口使用List對象作為方法返回值。
- resultMap
resultType 可以指定 pojo 將查詢結果映射為 pojo,但需要 pojo 的屬性名和 sql 查詢的列名一致方可映射成功。
如果sql查詢字段名和pojo的屬性名不一致,可以通過resultMap將字段名和屬性名作一個對應關系 ,resultMap實質上還需要將查詢結果映射到pojo對象中。
resultMap可以實現將查詢結果映射為復雜類型的pojo,比如在查詢結果映射對象中包括pojo和list實現一對一查詢和一對多查詢。
使用方法:
1、定義 resultMap
2、使用 resultMap 作為 statement 的輸出映射類型
將下面的 sql 使用 User 完成映射
select id id_, username username_ from user where id = #{value}User 類中屬性名和上邊查詢的列名不一致。
所以需要:
1、定義 resultMap
<!--定義 resultMap將select id id_, username username_ from user where id = #{value} 和User類中的屬性做一個映射關系type: resultMap最終映射的java對象類型id:對resultMap的唯一標識--><resultMap id="userResultMap" type="user"><!--id表示查詢結果中的唯一標識column:查詢出來的列名property:type指定pojo的屬性名最終resultMap對column和property做一個映射關系(對應關系)--><id column="id_" property="id"/><!--result: 對普通結果映射定義column:查詢出來的列名property:type指定pojo的屬性名最終resultMap對column和property做一個映射關系(對應關系)--><result column="username_" property="username"/></resultMap>2、使用 resultMap 作為 statement 的輸出映射類型
<!--使用 resultMap 作為輸出映射類型resultMap="userResultMap":其中的userResultMap就是我們剛才定義的 resultMap 的id值,如果這個resultMap在其他的mapper文件中,前邊須加上namespace --><select id="findUserByIdResultMap" parameterType="int" resultMap="userResultMap">select id id_, username username_ from user where id = #{value}</select>3、UserMapper.java
//根據id查詢用戶信息,使用 resultMap 輸出 public User findUserByIdResultMap(int id) throws Exception;4、測試
//測試根據id查詢用戶信息,使用 resultMap 輸出@Testpublic void testFindUserByIdResultMap() throws Exception{SqlSession sqlSession = sqlSessionFactory.openSession();//創建usermapper對象,mybatis自動生成代理對象UserMapper userMapper = sqlSession.getMapper(UserMapper.class);//調用UserMapper的方法User user = userMapper.findUserByIdResultMap(1);System.out.println(user);}5、測試結果
動態 SQL
通過mybatis提供的各種標簽方法實現動態拼接sql。
需求:
用戶信息綜合查詢列表和用戶信息查詢列表總數這兩個 statement的定義使用動態sql。
對查詢條件進行判斷,如果輸入的參數不為空才進行查詢條件拼接。
UserMapper.xml (findUserList的配置如下,那么findUserCount的也是一樣的,這里就不全部寫出來了)
<select id="findUserList" parameterType="cn.zhisheng.mybatis.po.UserQueryVo" resultType="cn.zhisheng.mybatis.po.UserCustom">select * from user<!--where可以自動的去掉條件中的第一個and--><where><if test="userCustom != null"><if test="userCustom.sex != null and userCustom.sex != ''">and user.sex = #{userCustom.sex}</if><if test="userCustom.username != null">and user.username like '%${userCustom.username}%'</if></if></where></select>測試代碼:因為設置了動態的sql,如果不設置某個值,那么條件就不會拼接在sql上
所以我們就注釋掉設置username的語句
//userCustom.setUsername("張小明");測試結果:
Sql 片段
通過上面的其實看到在 where sql語句中有很多重復代碼,我們可以將其抽取出來,組成一個sql片段,其他的statement就可以引用這個sql片段,利于系統的開發。
這里我們就拿上邊sql 中的where定義一個sq片段如下:
<!--sql片段id:唯一標識經驗:是基于單表來定義sql片段,這樣的話sql片段的可重用性才高一般不包含where--><sql id="query_user_where"><if test="userCustom != null"><if test="userCustom.sex != null and userCustom.sex != ''">and user.sex = #{userCustom.sex}</if><if test="userCustom.username != null">and user.username like '%${userCustom.username}%'</if></if></sql>那么我們該怎樣引用這個sql片段呢?如下:
select * from user<where><!--refid: 指定sql片段的id,如果是寫在其他的mapper文件中,則需要在前面加上namespace--><include refid="query_user_where"/></where>測試的話還是那樣了,就不繼續說了,前面已經說了很多了。
foreach
向sql傳遞數組或List,mybatis使用foreach解析
需求:
在用戶查詢列表和查詢總數的statement中增加多個id輸入查詢。
sql語句如下:
SELECT * FROM USER WHERE id=1 OR id=10 ORid=16 或者 SELECT * FROM USER WHERE id IN(1,10,16)在輸入參數類型中添加 List ids 傳入多個 id
public class UserQueryVo //用戶包裝類型 {//傳入多個idprivate List<Integer> ids; }修改 UserMapper.xml文件
WHERE id=1 OR id=10 OR id=16
在查詢條件中,查詢條件定義成一個sql片段,需要修改sql片段。
<if test="ids!=null"><!-- 使用 foreach遍歷傳入idscollection:指定輸入 對象中集合屬性item:每個遍歷生成對象中open:開始遍歷時拼接的串close:結束遍歷時拼接的串separator:遍歷的兩個對象中需要拼接的串--><!-- 使用實現下邊的sql拼接:AND (id=1 OR id=10 OR id=16) --><foreach collection="ids" item="user_id" open="AND (" close=")" separator="or"><!-- 每個遍歷需要拼接的串 -->id=#{user_id}</foreach><!-- 實現 “ and id IN(1,10,16)”拼接 --><!-- <foreach collection="ids" item="user_id" open="and id IN(" close=")" separator=",">每個遍歷需要拼接的串#{user_id}</foreach> --> </if>測試代碼:
//傳入多個id List<Integer> ids = new ArrayList<>(); ids.add(1); ids.add(10); ids.add(16); //將ids傳入statement中 userQueryVo.setIds(ids);期待后續的文章吧!
來源:http://blog.csdn.net/tzs_1041218129/article/details/53449052
null
總結
以上是生活随笔為你收集整理的通过项目逐步深入了解Mybatis二的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Django 电脑使用管理
- 下一篇: 它有什么本事,能成为Apache基金会项