轉載請務必註明出處,原創不易!java
一、 數據庫連接建立、釋放頻繁形成系統資源浪費從而影響系統性能,若是使用數據庫連接池可解決此問題。mysql
解決:在SqlMapConfig.xml中配置數據連接池,使用鏈接池管理數據庫連接。git
二、 Sql語句寫在代碼中形成代碼不易維護,實際應用sql變化的可能較大,sql變更須要改變java代碼。程序員
解決:將Sql語句配置在XXXXmapper.xml文件中與java代碼分離。github
三、 向sql語句傳參數麻煩,由於sql語句的where條件不必定,可能多也可能少,佔位符須要和參數一一對應。spring
解決:Mybatis自動將java對象映射至sql語句,經過statement中的parameterType定義輸入參數的類型。sql
四、 對結果集解析麻煩,sql變化致使解析代碼變化,且解析前須要遍歷,若是能將數據庫記錄封裝成pojo對象解析比較方便。數據庫
解決:Mybatis自動將sql執行結果映射至java對象,經過statement中的resultType定義輸出結果的類型。編程
Mybatis和hibernate不一樣,它不徹底是一個ORM框架,由於MyBatis須要程序員本身編寫Sql語句,不過mybatis能夠經過XML或註解方式靈活配置要運行的sql語句,並將java對象和sql語句映射生成最終執行的sql,最後將sql執行的結果再映射生成java對象。數組
Mybatis學習門檻低,簡單易學,程序員直接編寫原生態sql,可嚴格控制sql執行性能,靈活度高,很是適合對關係數據模型要求不高的軟件開發,例如互聯網軟件、企業運營類軟件等,由於這類軟件需求變化頻繁,一但需求變化要求成果輸出迅速。可是靈活的前提是mybatis沒法作到數據庫無關性,若是須要實現支持多種數據庫的軟件則須要自定義多套sql映射文件,工做量大。
Hibernate對象/關係映射能力強,數據庫無關性好,對於關係模型要求高的軟件(例如需求固定的定製化軟件)若是用hibernate開發能夠節省不少代碼,提升效率。可是Hibernate的學習門檻高,要精通門檻更高,並且怎麼設計O/R映射,在性能和對象模型之間如何權衡,以及怎樣用好Hibernate須要具備很強的經驗和能力才行。
總之,按照用戶的需求在有限的資源環境下只要能作出維護性、擴展性良好的軟件架構都是好架構,因此框架只有適合纔是最好。
原始 dao 開發方法(程序須要編寫 dao 接口和 dao 實現類)(掌握)
Mybatis 的 mapper 接口(至關於 dao 接口)代理開發方法(掌握)
將下邊的功能實現Dao:
根據用戶id查詢一個用戶信息
根據用戶名稱模糊查詢用戶信息列表
添加用戶信息
Mybatis 配置文件 SqlMapConfig.xml
SqlSession 中封裝了對數據庫的操做,如:查詢、插入、更新、刪除等。
經過 SqlSessionFactory 建立 SqlSession,而 SqlSessionFactory 是經過 SqlSessionFactoryBuilder 進行建立。
SqlSessionFactoryBuilder 用於建立 SqlSessionFacoty,SqlSessionFacoty 一旦建立完成就不須要SqlSessionFactoryBuilder 了,由於 SqlSession 是經過 SqlSessionFactory 生產,因此能夠將SqlSessionFactoryBuilder 當成一個工具類使用,最佳使用範圍是方法範圍即方法體內局部變量。
SqlSessionFactory 是一個接口,接口中定義了 openSession 的不一樣重載方法,SqlSessionFactory 的最佳使用範圍是整個應用運行期間,一旦建立後能夠重複使用,一般以單例模式管理 SqlSessionFactory。
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 實現類中注入 SqlsessionFactory ,在方法體內經過 SqlsessionFactory 建立 Sqlsession。
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; }
public class UserDaoImpl implements UserDao //dao接口實現類 { //須要在 Dao 實現類中注入 SqlsessionFactory //這裏經過構造方法注入 private SqlSessionFactory sqlSessionFactory; public UserDaoImpl(SqlSessionFactory sqlSessionFactory) { this.sqlSessionFactory = sqlSessionFactory; } @Override public User findUserById(int id) throws Exception { //在方法體內經過 SqlsessionFactory 建立 Sqlsession SqlSession sqlSession = sqlSessionFactory.openSession(); User user = sqlSession.selectOne("test.findUserById", id); sqlSession.close(); return user; } @Override public void insertUser(User user) throws Exception { //在方法體內經過 SqlsessionFactory 建立 Sqlsession SqlSession sqlSession = sqlSessionFactory.openSession(); //執行插入的操做 sqlSession.insert("test.insetrUser", user); //提交事務 sqlSession.commit(); //釋放資源 sqlSession.close(); } @Override public void deleteUser(int id) throws Exception { //在方法體內經過 SqlsessionFactory 建立 Sqlsession SqlSession sqlSession = sqlSessionFactory.openSession(); sqlSession.delete("test.deleteUserById", id); //提交事務 sqlSession.commit(); sqlSession.close(); } }
public class UserDaoImplTest { private SqlSessionFactory sqlSessionFactory; //此方法是在 testFindUserById 方法以前執行的 @Before public void setup() throws Exception { //建立sqlSessionFactory //Mybatis 配置文件 String resource = "SqlMapConfig.xml"; //獲得配置文件流 InputStream inputStream = Resources.getResourceAsStream(resource); //建立會話工廠,傳入Mybatis的配置文件信息 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } @Test public 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 方法使用泛型,即便變量類型傳入錯誤,在編譯階段也不報錯,不利於程序員開發。
程序員須要編寫 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 方法以前執行的 @Before public void setup() throws Exception { //建立sqlSessionFactory //Mybatis 配置文件 String resource = "SqlMapConfig.xml"; //獲得配置文件流 InputStream inputStream = Resources.getResourceAsStream(resource); //建立會話工廠,傳入Mybatis的配置文件信息 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } @Test public 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學習筆記 上看我這個項目的所有代碼)
經過姓名查詢用戶信息:
若是 mapper 方法返回單個 pojo 對象(非集合對象),代理對象內部經過 selectOne 查詢數據庫
若是 mapper 方法返回集合對象,代理對象內部經過 selectList 查詢數據庫
mapper 接口方法參數只能有一個,系統是否不利於維護?
系統框架中,dao層的代碼是被業務層公用的。
即便 mapper 接口只有一個參數,可使用包裝類型的 pojo 知足不一樣的業務方法的需求。
注意:持久層方法的參數能夠包裝類型、map.... ,service方法中不建議使用包裝類型。(不利於業務層的可擴展性)
Mybatis 的全局配置變量,配置內容和順序以下:
properties(屬性)
settings(全局配置參數)
typeAliases(類型別名)
typeHandlers(類型處理器)
objectFactory(對象工廠)
plugins(插件)
environments(環境集合屬性對象)
environment(環境子屬性對象)
transactionManager(事務管理)
dataSource(數據源)
mappers(映射器)
需求:將數據庫鏈接參數單獨配置在 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
Mybatis 框架在運行時能夠調整一些運行參數
好比:開啓二級緩存、開啓延遲加載。。。
需求:
在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>
測試結果:
mybatis中經過typeHandlers完成jdbc類型和java類型的轉換。
一般狀況下,mybatis提供的類型處理器知足平常須要,不須要自定義.
mybatis支持類型處理器:
類型處理器 | Java類型 | JDBC類型 |
---|---|---|
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-任何兼容的字符串類型,做爲代碼存儲(而不是索引)。 |
<mapper resource=" " />
使用相對於類路徑的資源,如:<mapper resource="sqlmap/User.xml" />
<mapper url=" " />
使用徹底限定路徑
如:<mapper url="file://D:workspacemybatisconfigsqlmapUser.xml" />
<mapper class=" " />
使用 mapper 接口類路徑
如:<mapper class="cn.zhisheng.mybatis.mapper.UserMapper"/>
注意:此種方法要求 mapper 接口名稱和 mapper 映射文件名稱相同,且放在同一個目錄中。
<mapper name=" " />
註冊指定包下的全部mapper接口
如:<package name="cn.zhisheng.mybatis.mapper"/>
注意:此種方法要求 mapper 接口名稱和 mapper 映射文件名稱相同,且放在同一個目錄中。
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;
測試代碼
//測試用戶信息綜合查詢 @Test public 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;
//測試用戶信息綜合查詢總數 @Test public 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指定的方法返回值類型不同:
一、輸出單個pojo對象,方法返回值是單個對象類型
//根據id查詢用戶信息 public User findUserById(int id) throws Exception;
二、輸出pojo對象list,方法返回值是List<Pojo>
//根據用戶名查詢用戶信息 public List<User> findUserByUsername(String userName) throws Exception;
resultType總結:
輸出pojo對象和輸出pojo列表在sql中定義的resultType是同樣的。
返回單個pojo對象要保證sql查詢出來的結果集爲單條,內部使用session.selectOne方法調用,mapper接口使用pojo對象做爲方法返回值。
返回pojo列表表示查詢出來的結果集可能爲多條,內部使用session.selectList方法,mapper接口使用List<pojo>對象做爲方法返回值。
resultMap
resultType 能夠指定 pojo 將查詢結果映射爲 pojo,但須要 pojo 的屬性名和 sql 查詢的列名一致方可映射成功。
若是sql查詢字段名和pojo的屬性名不一致,能夠經過resultMap將字段名和屬性名做一個對應關係 ,resultMap實質上還須要將查詢結果映射到pojo對象中。
resultMap能夠實現將查詢結果映射爲複雜類型的pojo,好比在查詢結果映射對象中包括pojo和list實現一對一查詢和一對多查詢。
使用方法:
一、定義 resultMap
二、使用 resultMap 做爲 statement 的輸出映射類型
將下面的 sql 使用 User 完成映射
select id id_, username username_ from user where id = #{value}
User 類中屬性名和上邊查詢的列名不一致。
因此須要:
一、定義 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>
二、使用 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>
三、UserMapper.java
//根據id查詢用戶信息,使用 resultMap 輸出 public User findUserByIdResultMap(int id) throws Exception;
四、測試
//測試根據id查詢用戶信息,使用 resultMap 輸出 @Test public 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); }
五、測試結果
經過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("張小明");
測試結果:
經過上面的其實看到在 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>
測試的話仍是那樣了,就不繼續說了,前面已經說了不少了。
向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<Integer> ids 傳入多個 id
public class UserQueryVo //用戶包裝類型 { //傳入多個id private List<Integer> ids; }
修改 UserMapper.xml文件
WHERE id=1 OR id=10 OR id=16
在查詢條件中,查詢條件定義成一個sql片斷,須要修改sql片斷。
<if test="ids!=null"> <!-- 使用 foreach遍歷傳入ids collection:指定輸入 對象中集合屬性 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);
期待後續的文章吧!