Hibernate:標準的ORM框架,不須要寫SQL語句,可是優化和修改SQL語句比較難。java
應用於需求變化固定的中小型的項目,例如後臺管理系統、ERP、ORM、OA。mysql
Mybatis:專一SQL自己,SQL的優化比較方便,是不徹底的ORM。程序員
主要適用於需求變化較多的項目,例如互聯網項目。spring
經過SqlSessionFactoryBuilder建立會話工廠SqlSessionFactory
將SqlSessionFactoryBuilder當成一個工具類使用便可,不須要使用單例管理SqlSessionFactoryBuilder。
在須要建立SqlSessionFactory時候,只須要new一次SqlSessionFactoryBuilder便可。sql
經過SqlSessionFactory建立SqlSession,使用單例模式管理sqlSessionFactory(工廠一旦建立,使用一個實例)。
mybatis和spring整合後,可使用Ioc容器管理。shell
SqlSession是一個面向用戶(程序員)的接口。
SqlSession中提供了不少操做數據庫的方法:如:selectOne(返回單個對象)、selectList(返回單個或多個對象)。
SqlSession是線程不安全的,在SqlSesion實現類中除了有接口中的方法(操做數據庫的方法)還有數據域屬性。
SqlSession最佳應用場合在方法體內,定義成局部變量使用。數據庫
程序員須要編寫DAO和DAO的實現類。須要向DAO實現類中注入SqlSessionFactory
,在方法體內經過SqlSessionFactory來建立SqlSession。數組
定義DAO接口緩存
public interface UserDAO { /** * 根據本id查詢用戶 */ User findUserById(int id) throws Exception; /** * 添加用戶 */ void insertUser(User user) throws Exception; /** * 根據id刪除用戶 */ void deleteUser(int id) throws Exception; }
DAO實現類安全
/** * @ClassName: UserDAOImpl * @Description: DAO實現類(注意:SqlSession是非線程安全的,故不能聲明爲全局的) */ public class UserDAOImpl implements UserDAO { SqlSessionFactory sqlSessionFactory; /** * 向DAO實現類中注入SqlSessionFactory(此處經過構造方法注入) */ public UserDAOImpl(SqlSessionFactory sqlSessionFactory) { this.sqlSessionFactory = sqlSessionFactory; } @Override public User findUserById(int id) throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); User user = sqlSession.selectOne("test.findUserById", id); sqlSession.close(); return user; } @Override public void insertUser(User user) throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); sqlSession.insert("test.insertUser", user); sqlSession.commit(); sqlSession.close(); } @Override public void deleteUser(int id) throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); sqlSession.delete("test.deleteUser", id); sqlSession.commit(); sqlSession.close(); } }
新建一個源代碼目錄命名爲test,在UserDAOImpl
類中鼠標右鍵新建一個Junit Test Case,更換源代碼目錄爲test並勾選咱們須要測試的方法:
public class UserDAOImplTest { private SqlSessionFactory sqlSessionFactory; /** * 此方法在執行測試以前執行,獲得一個SqlSessionFactory */ @Before public void setUp() throws Exception { sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("SqlMapConfig.xml")); } @Test public void testFindUserById() throws Exception { // 建立UserDAO(在構造中注入SqlSessionFactory) UserDAO userDAO = new UserDAOImpl(sqlSessionFactory); User user = userDAO.findUserById(1); System.out.println(user); } @Test public void testInsertUser() throws Exception { UserDAO userDAO = new UserDAOImpl(sqlSessionFactory); User user = new User(); user.setSex("2"); user.setUsername("孫悟空"); user.setAddress("方寸靈臺山"); user.setBirthday(new Date()); userDAO.insertUser(user); } @Test public void testDeleteUser() throws Exception { UserDAO userDAO = new UserDAOImpl(sqlSessionFactory); userDAO.deleteUser(27); } }
DAO的接口實現類中存在大量的模板方法,設想:能夠將重複的代碼提取出來。
在SqlSession的方法時將Statement的id硬編碼在你DAO的實現類中。
調用sqlSession的相關方法傳入參數是泛型,即便傳入錯誤的參數,編譯時候也不會報錯。
程序員只須要編寫Mapper接口(至關於DAO接口)和Mapper.xml。Mapper接口的編寫須要遵照相關規範:
mapper.xml中的命名空間等於Mapper接口類的全路徑;
mapper.java中的方法名和mapper.xml中的statement的id一致;
mapper接口中方法的輸入參數類型和mapper.xml中的ParameterType一致;
mapper接口中的方法的返回值類型和mapper.xml中的ResultType一致。
遵循以上規範,mybatis就能夠自動生成(反射機制)相關的mapper代理的實現類的對象。
UserMapper.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"> <!-- 命名空間用來對SQL進行分類管理(SQL隔離) 此處採用Mapper代理開發,命名空間爲Mapper接口的地址 --> <mapper namespace="org.gpf.mapper.UserMapper"> <!-- statement的id和Mapper接口中的方法名一致 parameterType和Mapper接口中的方法參數一致 resultType和Mapper接口中的方法返回值一致 --> <!-- 根據id查詢用戶 --> <select id="findUserById" parameterType="int" resultType="org.gpf.po.User"> SELECT * FROM user WHERE id = #{id}; </select> <!-- 根據用戶名查找用戶 --> <select id="findUsersByName" parameterType="java.lang.String" resultType="org.gpf.po.User"> <!-- 易出錯 SELECT * FROM user WHERE username LIKE #{value}; --> <!-- 使用${}進行SQL拼接 --> SELECT * FROM user WHERE username LIKE '%${value}%'; </select> <!-- 添加用戶 --> <insert id="insertUser" parameterType="org.gpf.po.User"> <selectKey keyProperty="id" order="AFTER" resultType="int"> SELECT LAST_INSERT_ID(); </selectKey> INSERT INTO user(username,birthday,sex,address) VALUES(#{username},#{birthday},#{sex},#{address}); </insert> <!-- 刪除用戶 --> <delete id="deleteUser" parameterType="java.lang.Integer"> DELETE FROM user WHERE id = #{id} </delete> <!-- 更新用戶 --> <update id="updateUser" parameterType="org.gpf.po.User"> UPDATE user SET username = #{username},birthday=#{birthday},sex=#{sex},address=#{address} WHERE id = #{id} </update> </mapper>
UserMapper.java
/** * @Description: 用戶管理相關Mapper接口 */ public interface UserMapper { /** * 根據本id查詢用戶 */ User findUserById(int id) throws Exception; /** * 根據用戶名模糊查詢用戶 */ List<User> findUsersByName(String name) throws Exception; /** * 添加用戶 */ void insertUser(User user) throws Exception; /** * 根據id刪除用戶 */ void deleteUser(int id) throws Exception; }
完成前面2步以後不要忘了在映射文件SqlMapConfig.xml中加載UserMapper.xml哦!
<!-- 配置映射文件 --> <mappers> <mapper resource="sqlmap/User.xml"/> <mapper resource="mapper/UserMapper.xml"/> </mappers>
針對UserMapper接口編寫Junit單元測試:
public class UserMapperTest { private SqlSessionFactory sqlSessionFactory; @Before public void setUp() throws Exception { sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("SqlMapConfig.xml")); } @Test public void testFindUserById() throws Exception { // 獲得SqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); // 獲得UserMapper對象(Mybatis自動生成Mapper代理對象) UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // 調用UserMapper的方法 User user = userMapper.findUserById(1); System.out.println(user); // 關閉SqlSession sqlSession.close(); } @Test public void testFindUsersByName() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> users = userMapper.findUsersByName("明"); System.out.println(users); sqlSession.close(); } @Test public void testInsertUser() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User user = new User(); user.setAddress("晴川"); user.setUsername("百里屠蘇"); user.setBirthday(new Date()); user.setSex("1"); userMapper.insertUser(user); sqlSession.commit(); sqlSession.close(); System.out.println(user.getId()); } @Test public void testDeleteUser() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); userMapper.deleteUser(28); sqlSession.commit(); sqlSession.close(); } }
咱們比較疑問的就是咱們在UserMapper.xml的根據用戶名查找用戶的ResultType使用的是普通的POJO,可是咱們本身的Mapper接口中返回值是List類型。這不就形成了類型不一致麼?可是,實際上代理對象內部調用了selectOne()
或者selectList()
,代理對象內部會自動進行判斷是不是單獨的POJO選用合適的方法。
Mapper接口中方法的參數只有一個是否會影響系統的維護?DAO層的代碼是被業務層公用的,即便Mapper接口的參數只有一個咱們也可使用包裝的POJO來知足系統需求。
注意:持久層中方法的參數中可使用包裝類型,可是Service層中不建議使用包裝類型(不利於業務層的拓展維護)。
該配置文件是mybatis的全局配置文件,配置內容以下:
properties(屬性) settings(全局配置參數) typeAliases(類型別名) typeHandlers(類型處理器) objectFactory(對象工廠) plugins(插件) environments(環境集合屬性對象) environment(環境子屬性對象) transactionManager(事務管理) dataSource(數據源) mappers(映射器)
將數據庫鏈接參數單獨配置在db.properties中,只須要在SqlMapConfig.xml中加載db.properties的屬性值。
在SqlMapConfig.xml中就不須要對數據庫鏈接參數硬編碼。
將數據庫鏈接參數只配置在db.properties中,緣由:方便對參數進行統一管理,其它xml能夠引用該db.properties。
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mybatis jdbc.username=root jdbc.password=mysqladmin
在SqlMapConfig中加載屬性文件:
<?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 resource="db.properties"> <!-- 通常不建議在這裏配置屬性 <property name="jdbc.driver" value="com.mysql.jdbc.Driver"/> --> </properties> <!-- 與Spring整合後該配置將會被移除 --> <environments default="development"> <environment id="development"> <!-- 使用JDBC事務進行管理,事務的控制由mybatis管理 --> <transactionManager type="JDBC"> <property name="" value="" /> </transactionManager> <!-- 從屬性文件中取出數據庫的配置信息 --> <dataSource type="UNPOOLED"> <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> </configuration>
properties特性:
注意: MyBatis 將按照下面的順序來加載屬性:
在 properties 元素體內定義的屬性首先被讀取。
而後會讀取properties 元素中resource或 url 加載的屬性,它會覆蓋已讀取的同名屬性。
最後讀取parameterType傳遞的屬性,它會覆蓋已讀取的同名屬性。
建議:
不要在properties元素體內添加任何屬性值,只將屬性值定義在properties文件中。在properties文件中定義屬性名要有必定的特殊性(防止覆蓋),如:XXXXX.XXXXX.XXXX
settings配置全局參數,mybatis在運行時能夠調整一些運行參數。例如:開啓二級緩存、開啓延遲加載。參數詳見:Mybatis settings詳解
在mapper.xml中,定義不少的statement,statement須要parameterType指定輸入參數的類型、須要resultType指定輸出結果的映射類型。
若是在指定類型時輸入類型全路徑,不方便進行開發,能夠針對parameterType或resultType指定的類型定義一些別名,在mapper.xml中經過別名定義,方便開發。
在SqlMapConfig.xml中配置別名:
<!-- 別名定義 --> <typeAliases> <!-- 針對單個別名定義 type:類型的路徑 alias:別名 --> <typeAlias type="org.gpf.po.User" alias="user"/> </typeAliases>
在mapperr.xml中使用別名替代ResultType:
<!-- 根據id查詢用戶 此處的resultType指定爲SqlMapConfig.xml中配置的別名 --> <select id="findUserById" parameterType="int" resultType="user"> SELECT * FROM user WHERE id = #{id}; </select>
以上的方法是定義簡單的單個別名,咱們也可使用批量別名定義:
<!-- 別名定義 --> <typeAliases> <!-- 批量別名定義 指定包名,mybatis自動掃描包中的po類,自動定義別名,別名就是類名(首字母大寫或小寫均可以) --> <package name="org.gpf.po"/> </typeAliases>
在mapper.xml中咱們可使用以上的別名,此時是大小寫不敏感的:
<!-- 根據id查詢用戶 此處的resultType指定爲SqlMapConfig.xml中配置的別名 --> <select id="findUserById" parameterType="int" resultType="User"> SELECT * FROM user WHERE id = #{id}; </select>
其中批量設置別名比較經常使用(只須要配置po所在的類路徑便可)。
類型處理器,mybatis經過typeHandlers完成JDBC類型和java類型的轉化。通常來講自帶的類型處理器已經夠用了,不須要單獨定義。
映射配置。
經過resource一次加載一個映射文件:
經過mapper接口加載單個映射文件,須要遵循相關的規範:將mapper.xml和mapper接口的名稱保持一致且在一個目錄中(前提是使用mapper代理的方式進行開發)。
批量加載mapper。一樣須要遵照上面的規範。
經過parameterType來指定輸入參數的類型,能夠是簡單類型、hashmap、pojo。
需求:完成用戶信息的綜合查詢,須要傳入查詢條件很複雜(可能包括用戶信息、其它信息,好比商品、訂單的)
針對上邊需求,建議使用自定義的包裝類型的pojo。在包裝類型的pojo中將複雜的查詢條件包裝進去。
新建一個UserCustomer類(該類繼承User,實現對Us而的拓展)
/** * @ClassName: UserCustom * @Description: 用戶拓展類 */ public class UserCustom extends User { }
新建一個UserQueryVO(在該類內部以組合的方式包裝UserCustomer類)
/** * @ClassName: UserQueryVO * @Description: 視圖層面javabean(用來包裝查詢條件) */ public class UserQueryVO { // 包裝所須要的查詢條件(能夠經過組合的方式包裝其餘的查詢條件,例如:商品、訂單) private UserCustom userCustom; public UserCustom getUserCustom() { return userCustom; } public void setUserCustom(UserCustom userCustom) { this.userCustom = userCustom; } }
mapper.xml。在UserMapper.xml中定義用戶信息的綜合(複雜的關聯查詢)查詢。
<!-- 用戶信息的綜合查詢 #{UserCustom.sex} 取出POJO包裝類型中用戶的性別(注意大小寫:OGNL表達式) --> <select id="findUserList" parameterType="org.gpf.po.UserQueryVO" resultType="org.gpf.po.UserCustom"> SELECT * FROM user WHERE user.sex = #{userCustom.sex} OR user.username LIKE '%${userCustom.username}%' </select>
mapper.java。在UserMapper接口中增長一個方法。
/** * 用戶信息的綜合查詢 */ List<UserCustom> findUserList(UserQueryVO userQueryVO) throws Exception;
測試類
@Test public void testfindUserList() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // 建立包裝對象,傳入查詢條件 UserQueryVO userQueryVO = new UserQueryVO(); UserCustom userCustom = new UserCustom(); userCustom.setSex("1"); userCustom.setUsername("明"); userQueryVO.setUserCustom(userCustom); List<UserCustom> users = userMapper.findUserList(userQueryVO); System.out.println(users); }
使用ResultType進行輸出映射只有當查詢輸出列名和POJO中的字段名一致時,該列才能夠映射成功;若是查詢出來的列名和屬性名所有不一致(例如使用了SQL的別名);一旦有一個查詢的輸出列名和POJO的屬性名一致就會映射成對象。
需求:用戶信息的綜合查詢列表總數,並結合上邊的綜合查詢列表實現分頁功能。
mapper.xml
<!-- 用戶信息的綜合查詢總數(分頁的基礎) COUNT(*) 和COUNT(1)、COUNT(2)同樣 --> <select id="findUserCount" parameterType="org.gpf.po.UserQueryVO" resultType="int"> SELECT COUNT(1) FROM user WHERE user.sex = #{userCustom.sex} OR user.username LIKE '%${userCustom.username}%' </select>
mapper.java
/** * 用戶信息的綜合查詢總數 */ int findUserCount(UserQueryVO userQueryVO) throws Exception;
測試類:
@Test public void testFindUserCount() throws Exception{ SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // 建立包裝對象,傳入查詢條件 UserQueryVO userQueryVO = new UserQueryVO(); UserCustom userCustom = new UserCustom(); userCustom.setSex("1"); userCustom.setUsername("明"); userQueryVO.setUserCustom(userCustom); int count = userMapper.findUserCount(userQueryVO); System.out.println(count); }
小結:
查詢出來的結果集只有一行且一列,可使用簡單類型進行輸出映射。
輸出POJO對象和POJO列表。
不論是輸出的pojo單個對象仍是一個列表(list中包括pojo),在mapper.xml中resultType指定的類型是同樣的。
在mapper.java指定的方法返回值類型不同。
生成的動態代理對象中是根據mapper方法的返回值類型肯定是調用selectOne(返回單個對象調用)仍是selectList (返回集合對象調用 ).
可使用ResultMap來完成高級的輸出結果映射。若是數據庫輸出的列名和POJO的屬性名不一致,就能夠經過定義ResultMap對列名和屬性名進行咱們本身的映射。
範例:使用ResultMap改寫如下的SQL,完成輸出結果的映射;
SELECT id _id,username _username FROM user WHERE id = #{value}
UserMapper.xml
<!-- 定義ResultMap 將SELECT id _id,username _username FROM user和User類中的屬性進行映射 type:ResultType最終映射的java對象的類型(可以使用別名) id:ResultMap的惟一標識 --> <resultMap type="org.gpf.po.User" id="userResultMap"> <!-- id:查詢結果集中的惟一標識,column:查詢出的列名,property:POJO的屬性名,最終column和property具備映射關係 --> <id column="_id" property="id" /> <!-- 普通名映射定義 --> <result column="_username" property="username"/> </resultMap> <!-- 使用ResultMap進行輸出的映射 resultMap:指定定義的ResultMap的id,若是ResultMap在其餘文件中須要指定命名空間 --> <select id="findUserByIdResultMap" parameterType="int" resultMap="userResultMap"> SELECT id _id,username _username FROM user WHERE id = #{value} </select>
UserMapper.java
/** * 根據id查詢用戶(經過ResultMap手工完成映射) */ User findUserByIdResultMap(int id) throws Exception;
測試類:
@Test public void testFindUserByIdResultMap() throws Exception{ SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User user = userMapper.findUserByIdResultMap(1); System.out.println(user); sqlSession.close(); }
小結:
使用resultType進行輸出映射,只有查詢出來的列名和pojo中的屬性名一致,該列才能夠映射成功。
若是查詢出來的列名和pojo的屬性名不一致,經過定義一個resultMap對列名和pojo屬性名之間做一個映射關係。
mybatis核心對sql語句進行靈活操做,經過表達式進行判斷,對sql進行靈活拼接、組裝。
需求:用戶信息綜合查詢列表和用戶信息查詢列表總數這兩個statement的定義使用動態sql。對查詢條件進行判斷,若是輸入參數不爲空才進行查詢條件拼接。
if判斷相似於JSTL.
mapper.xml
<!-- 動態SQL --> <select id="findUserList" parameterType="org.gpf.po.UserQueryVO" resultType="org.gpf.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 userCustom.username != ''"> AND user.username LIKE '%${userCustom.username}%' </if> </if> </where> </select> <select id="findUserCount" parameterType="org.gpf.po.UserQueryVO" resultType="int"> SELECT COUNT(1) FROM 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 userCustom.username != ''"> AND user.username LIKE '%${userCustom.username}%' </if> </if> </where> </select>
maper.java
/** * 用戶信息的綜合查詢 */ List<UserCustom> findUserList(UserQueryVO userQueryVO) throws Exception; /** * 用戶信息的綜合查詢總數 */ int findUserCount(UserQueryVO userQueryVO) throws Exception;
測試類
@Test public void testfindUserList() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // 取消部分查詢條件 UserQueryVO userQueryVO = new UserQueryVO(); UserCustom userCustom = new UserCustom(); // userCustom.setSex("1"); userCustom.setUsername("明"); userQueryVO.setUserCustom(userCustom); List<UserCustom> users = userMapper.findUserList(userQueryVO); System.out.println(users); } @Test public void testFindUserCount() throws Exception{ SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // 取消部分查詢條件 UserQueryVO userQueryVO = new UserQueryVO(); UserCustom userCustom = new UserCustom(); userCustom.setSex("1"); // userCustom.setUsername("明"); userQueryVO.setUserCustom(userCustom); int count = userMapper.findUserCount(userQueryVO); System.out.println(count); }
以上的代碼中mapper.xml中的SQL語句有一些重複,咱們能夠將上面的動態SQL中共有的部分抽取出來造成本身的sql片斷,在其餘的Statement中就可使用此SQL片斷。
定義並使用SQL片斷
<!-- 定義SQL片斷 id:SQL片斷的惟一標識 經驗:SQL片斷通常是基於單表的,這樣的話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 userCustom.username != ''"> AND user.username LIKE '%${userCustom.username}%' </if> </if> </sql> <select id="findUserCount" parameterType="org.gpf.po.UserQueryVO" resultType="int"> SELECT COUNT(1) FROM user <where> <!-- 使用SQL片斷,若是不在本文件中須要加上命名空間 --> <include refid="query_user_where"></include> </where> </select>
向sql傳遞數組或List,mybatis使用foreach解析。
例如:在用戶查詢列表和查詢總數的statement中增長多個id輸入查詢。
兩種方法:
SELECT * FROM USER WHERE id=1 OR id=10 OR id=16 SELECT * FROM USER WHERE id IN(1,10,16)
在輸入參數類型中添加List<Integer>
ids傳入多個id(並添加getter和setter)
修改mapper.xml中的SQL片斷
<!-- 定義SQL片斷 id:SQL片斷的惟一標識 經驗:SQL片斷通常是基於單表的,這樣的話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 userCustom.username != ''"> AND user.username LIKE '%${userCustom.username}%' </if> </if> <if test="ids != null"> <!-- 使用for-each遍歷傳入的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> </if> </sql>
測試類:
@Test public void testfindUserList() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); UserQueryVO userQueryVO = new UserQueryVO(); UserCustom userCustom = new UserCustom(); userCustom.setUsername("明"); // 傳入多個id List<Integer> ids = Arrays.asList(1,16,22,25); userQueryVO.setId(ids); userQueryVO.setUserCustom(userCustom); List<UserCustom> users = userMapper.findUserList(userQueryVO); System.out.println(users); }
<!-- 實現 and id IN(1,10,16)拼接 --> <foreach collection="ids" item="user_id" open="and id IN(" close=")" separator=","> 每一個遍歷須要拼接的串 #{user_id} </foreach>