MyBatis框架流程


Hibernate與Mybatis的本質區別和應用場景

  • Hibernate:標准的ORM框架,不需要寫SQL語句,但是優化和修改SQL語句比較難。

    • 應用於需求變化固定的中小型的項目,例如后台管理系統、ERP、ORM、OA。

  • Mybatis:專注SQL本身,SQL的優化比較方便,是不完全的ORM。

    • 主要適用於需求變化較多的項目,例如互聯網項目。

mybatis開發dao的方法

SqlSession的應用場合

SqlSessionFactoryBuilder

通過SqlSessionFactoryBuilder創建會話工廠SqlSessionFactory
將SqlSessionFactoryBuilder當成一個工具類使用即可,不需要使用單例管理SqlSessionFactoryBuilder。
在需要創建SqlSessionFactory時候,只需要new一次SqlSessionFactoryBuilder即可。

SqlSessionFactory

通過SqlSessionFactory創建SqlSession,使用單例模式管理sqlSessionFactory(工廠一旦創建,使用一個實例)。
mybatis和spring整合后,可以使用Ioc容器管理。

SqlSession

SqlSession是一個面向用戶(程序員)的接口。
SqlSession中提供了很多操作數據庫的方法:如:selectOne(返回單個對象)、selectList(返回單個或多個對象)。
SqlSession是線程不安全的,在SqlSesion實現類中除了有接口中的方法(操作數據庫的方法)還有數據域屬性。
SqlSession最佳應用場合在方法體內,定義成局部變量使用。

原始的DAO開發方法

程序員需要編寫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開發中存在的問題

  • DAO的接口實現類中存在大量的模板方法,設想:可以將重復的代碼提取出來。

  • 在SqlSession的方法時將Statement的id硬編碼在你DAO的實現類中。

  • 調用sqlSession的相關方法傳入參數是泛型,即使傳入錯誤的參數,編譯時候也不會報錯。

Mapper接口開發

程序員只需要編寫Mapper接口(相當於DAO接口)和Mapper.xml。Mapper接口的編寫需要遵守相關規范:

  1. mapper.xml中的命名空間等於Mapper接口類的全路徑;

  2. mapper.java中的方法名和mapper.xml中的statement的id一致;

  3. mapper接口中方法的輸入參數類型和mapper.xml中的ParameterType一致;

  4. 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層中不建議使用包裝類型(不利於業務層的拓展維護)。

SqlMapConfig.xml文件

屬性配置

該配置文件是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

settings配置全局參數,mybatis在運行時可以調整一些運行參數。例如:開啟二級緩存、開啟延遲加載。參數詳見:Mybatis settings詳解

typeAliases

在mapper.xml中,定義很多的statement,statement需要parameterType指定輸入參數的類型、需要resultType指定輸出結果的映射類型。

如果在指定類型時輸入類型全路徑,不方便進行開發,可以針對parameterType或resultType指定的類型定義一些別名,在mapper.xml中通過別名定義,方便開發。

mybatis內置的別名

自定義別名

在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所在的類路徑即可)。

TypeHandlers

類型處理器,mybatis通過typeHandlers完成JDBC類型和java類型的轉化。一般來說自帶的類型處理器已經夠用了,不需要單獨定義。

mapper

映射配置。

  • 通過resource一次加載一個映射文件:

  • 通過mapper接口加載單個映射文件,需要遵循相關的規范:將mapper.xml和mapper接口的名稱保持一致且在一個目錄中(前提是使用mapper代理的方式進行開發)。


  • 批量加載mapper。同樣需要遵守上面的規范。

輸入映射

通過parameterType來指定輸入參數的類型,可以是簡單類型、hashmap、pojo。

傳遞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

使用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

可以使用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屬性名之間作一個映射關系。

動態SQL

mybatis核心對sql語句進行靈活操作,通過表達式進行判斷,對sql進行靈活拼接、組裝。

if判斷

需求:用戶信息綜合查詢列表和用戶信息查詢列表總數這兩個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); }

sql片段

以上的代碼中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>

for-each

向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>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM