MyBatis(二)參數傳遞和自定義結果集


個人博客網:https://wushaopei.github.io/    (你想要這里多有)

一、myBatis的注解使用方式

package com.webcode.mapper; import java.util.List; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.SelectKey; import org.apache.ibatis.annotations.Update; import com.webcode.pojo.User; public interface UserMapper { @Select("select id,last_name lastName,sex from t_user where id = #{id}") public User queryUserById(Integer id); //@Select("select id,last_name lastName,sex from t_user") public List<User> queryUsers(); @SelectKey(statement = "select last_insert_id()", before = false, keyProperty = "id", resultType = Integer.class) @Insert(value = "insert into t_user(last_name,sex) values(#{lastName},#{sex})") public int saveUser(User user); @Delete("delete from t_user where id = #{id}") public int deleteUserById(Integer id); @Update("update t_user set last_name = #{lastName},sex = #{sex} where id = #{id}") public int updateUser(User user); }

二、mybatis的參數傳遞

1、一個普通數據類型

Mapper接口的方法:

public interface UserMapper { public User queryUserById(Integer id); }

mapper.xml配置文件:

<select id="queryUserById" resultType="com.webcode.pojo.User">
		select id,last_name lastName,sex from t_user where id = #{id}
	</select>

2、多個普通數據類型

方法代碼:

	public List<User> queryUserByNameAndSex(String name, Integer sex); 

配置文件:

<select id="queryUserByNameAndSex" resultType="com.webcode.pojo.User">
		<!-- 
			多個普通類型的參數,在配置sql語句的時候,
			方案一:那么在#{}占位符中,可以寫0,1
			0表示第一個參數,1表示第二個參數。(不推薦使用)
			
			方案二:那么在#{}占位符中,可以寫param1,param2……
			param1表示第一參數
			param2表示第二個參數
			以此類推 第n個參數,就是paramn
		 -->
		select id,last_name lastName,sex from t_user where last_name = #{param1} and sex = #{param2}
	</select>

2、@Param注解命名參數

方法代碼:

public List<User> queryUserByNameAndSex(@Param("name") String name,
			@Param("sex") Integer sex);

配置信息:

<select id="queryUserByNameAndSex" resultType="com.webcode.pojo.User">
	<!-- 
		public List<User> queryUserByNameAndSex(@Param("name") String name,
			@Param("sex") Integer sex);
		當我們在方法的參數上使用了@Param注解給參數進行全名之后,我們可以在配置的sql語句中的占位符里寫中參數的名
		 -->
		select id,last_name lastName,sex from t_user where last_name = #{name} and sex = #{sex}
	</select>

3、傳遞一個Map對象作為參數

方法代碼:

/**
	 * Map<String, Object> param,我們希望在Map中放name的值和sex的值,來進行查詢
	 */
	public List<User> queryUserByMap(Map<String, Object> param);

配置信息:

<select id="queryUserByMap" resultType="com.webcode.pojo.User">
		<!-- 
			當參數是Map類型的時候,sql語句中的參數名必須和map的key一致
			map.put("name",xxx);
			map.put("sex",xxx);
		 -->
		select id,last_name lastName,sex from t_user where last_name = #{name} and sex = #{sex}
	</select>

4、一個JavaBean數據類型

方法代碼:

/** * 我們希望使用user對象的lastName屬性和sex屬性,來進行查詢 */ public List<User> queryUserByUser(User user);

配置信息:

<select id="queryUserByUser" resultType="com.webcode.pojo.User">
		<!-- 當傳遞的參數是javaBean對象的時候,在sql語句的配置的占位符中,使用屬性名 -->
		select id,last_name lastName,sex from t_user where last_name = #{lastName} and sex = #{sex}
	</select>

5、多個Pojo數據類型

方法代碼:

/** * 我們希望使用第一個user對象的lastName屬性和第二個user對象的sex屬性,來進行查詢 */ public List<User> queryUserByUsers(User name,User sex);

配置信息:

<select id="queryUserByUsers" resultType="com.webcode.pojo.User">
	<!-- 
		如果參數是多個javaBean的時候,
		第一個javaBean是param1,第二個javaBean是param2.以此類推。
		但我們使用的只是javaBean的屬性。#{param1.屬性名}	就表示使用第一個javaBean的某個屬性的值
	 -->
		select id,last_name lastName,sex from t_user where last_name = #{param1.lastName} and sex = #{param2.sex}
	</select>

6、模糊查詢

需求:現在要根據用戶名查詢用戶對象。 也就是希望查詢如下: select * from t_user where last_name like '%張%'

方法代碼:

/** * 需求:現在要根據用戶名查詢用戶對象。 也就是希望查詢如下:<br/> * select * from t_user where last_name like '%張%' */ public List<User> queryUsersByNameLike(String lastName); 

7、#{}和${}的區別

#{} 是占位符

${} 是做字符串原樣輸出,然后和配置的sql語句做字符串拼接。

8、MySQL的字符串拼接,concat函數實現。

<select id="queryUsersByNameLike" resultType="com.webcode.pojo.User">
	<!-- 
		#{}		是占位符
		${}		是字符串原樣輸出,然后做字符串拼接(有sql注入的風險)
		concat 是mysql提供的字符串拼接函數。
	 -->
		select id,last_name lastName,sex from t_user where last_name like concat('%',#{lastName},'%')
	</select>

二、自定義結果集<resultMap></resultMap> 

1、<resultMap>的作用。

ResultMap標簽可以給那些查詢出來的結果要封裝成為的Bean對象。是復雜bean對象的情況。

原來我們查詢出來的結果,封裝的對象里面的屬性都是普通的屬性。不包含子的javaBean對象。也不包含Bean對象的集合。那種叫普通的javabean。

那些Bean對象中又包含了子的Bean對象的情況,或者是Bean對象中又包含的bean對象集合的情況,叫復雜的Bean對象。

這種情況,只能使用ResultMap標簽來將結果集轉換成為復雜的Bean對象。而簡單的不需要。簡單的Bean對象,只需要使用ResultType屬性即可。

2、創建一對一數據庫表

## 一對一數據表
## 創建鎖表
create table t_lock(
	`id` int primary key auto_increment,
	`name` varchar(50)
);

## 創建鑰匙表
create table t_key(
	`id` int primary key auto_increment,
	`name` varchar(50),
	`lock_id` int ,
	foreign key(`lock_id`) references t_lock(`id`)
);

## 插入初始化數據
insert into t_lock(`name`) values('阿里巴巴');
insert into t_lock(`name`) values('華為');
insert into t_lock(`name`) values('聯想');

insert into t_key(`name`,`lock_id`) values('馬雲',1);
insert into t_key(`name`,`lock_id`) values('任正非',2);
insert into t_key(`name`,`lock_id`) values('柳傳志',3);

3、創建實體對象

public class Lock { private Integer id; private String name; public class Key { private Integer id; private String name; private Lock lock;

4、一對一級聯屬性使用

Mapper接口的代碼:

public interface KeyMapper { public Key queryKeyByIdForSample(Integer id); }

KeyMapper配置文件的內容:

<!-- resultMap可以自定義結果集 type屬性設置你要封裝成為什么類型返回 id屬性給resultMap集合集起一個唯一的標識 --> <resultMap type="com.webcode.pojo.Key" id="queryKeyByIdForSample_resultMap"> <!-- id標簽負責把數據庫的主鍵列。轉到對象的id屬性中 column是列名 property是屬性名 把列名的值,注入到property屬性指向的屬性中 --> <id column="id" property="id"/> <!-- 非主鍵列使用result標簽 --> <result column="name" property="name"/> <!-- 級聯映射 一級一級的關聯 --> <result column="lock_id" property="lock.id"/> <result column="lock_name" property="lock.name"/> </resultMap> <!-- public Key queryKeyByIdForSample(Integer id); --> <select id="queryKeyByIdForSample" resultMap="queryKeyByIdForSample_resultMap"> select t_key.* ,t_lock.name lock_name from t_key left join t_lock on t_key.lock_id = t_lock.id where t_key.id = #{id} </select>

4.2、<association /> 嵌套結果集映射配置

<resultMap type="com.webcode.pojo.Key" id="queryKeyByIdForSample_association_resultMap"> <id column="id" property="id"/> <!-- 非主鍵列使用result標簽 --> <result column="name" property="name"/> <!-- association標簽可以把查詢的結果映射成為一個子對象 property="lock" 你要映射哪個子對象 javaType 是說明你要映射出來的子對象是什么類型 --> <association property="lock" javaType="com.webcode.pojo.Lock"> <!-- id給主鍵進行配置 --> <id column="lock_id" property="id"/> <!-- result給非主鍵列進行配置 --> <result column="lock_name" property="name"/> </association> </resultMap> <!-- public Key queryKeyByIdForSample(Integer id); --> <select id="queryKeyByIdForSample" resultMap="queryKeyByIdForSample_association_resultMap"> select t_key.* ,t_lock.name lock_name from t_key left join t_lock on t_key.lock_id = t_lock.id where t_key.id = #{id} </select>

4.3、<association /> 定義分步(立即)查詢

KeyMapper接口:

public interface KeyMapper { // 分兩次查,只查key public Key queryKeyByIdForTwoStep(Integer id); }

LockMapper接口:

public interface LockMapper { // 只查鎖 public Lock queryLockById(Integer id); }

LockMapper配置信息:

<mapper namespace="com.webcode.mapper.LockMapper"> <!-- public Lock queryLockById(Integer id); 第二次查,只查鎖的情況 --> <select id="queryLockById" resultType="com.webcode.pojo.Lock"> select id,name from t_lock where id = #{id} </select> </mapper>

KeyMapper的配置信息:

	<resultMap type="com.webcode.pojo.Key" id="queryKeyByIdForTwoStep_resultMap"> <id column="id" property="id"/> <result column="name" property="name"/> <!-- association需要配置當前的這個子對象是使用一次查詢得到 property="lock" 表示當前要配置哪個子對象 select表示你要使用哪個查詢來得到這個子對象(需要一個參數) column表示你要將原查詢結果的哪個列做為參數傳遞給下一個查詢使用。 --> <association property="lock" column="lock_id" select="com.webcode.mapper.LockMapper.queryLockById"/> </resultMap> <!-- 分兩次查,只查key public Key queryKeyByIdForTwoStep(Integer id); --> <select id="queryKeyByIdForTwoStep" resultMap="queryKeyByIdForTwoStep_resultMap"> select id,name,lock_id from t_key where id = #{id} </select>

5、延遲加載

延遲加載在一定程序上可以減少很多沒有必要的查詢。給數據庫服務器提升性能上的優化。

要啟用延遲加載,需要在mybatis-config.xml配置文件中,添加如下兩個全局的settings配置。

<!-- 打開延遲加載的開關 --> <setting name="lazyLoadingEnabled" value="true" /> <!-- 將積極加載改為消極加載 按需加載 --> <setting name="aggressiveLazyLoading" value="false"/> 

懶加載還需要同時引入兩個jar包(注意: 3.2.8版本需要導以下兩個包)

5.2、延遲加載的一對一使用示例

	<settings> <!-- 自動開啟駝峰命名 --> <setting name="mapUnderscoreToCamelCase" value="true" /> <!-- 打開延遲加載的開關 --> <setting name="lazyLoadingEnabled" value="true" /> <!-- 將積極加載改為消極加載 按需加載 --> <setting name="aggressiveLazyLoading" value="false" /> </settings>

三、多對一、一對多的使用示例

1、創建一對多數據庫

## 一對多數據表
## 創建班級表
create table t_clazz(
	`id` int primary key auto_increment,
	`name` varchar(50)
);

## 插入班級信息
insert into t_clazz(`name`) values('javaEE20170228');
insert into t_clazz(`name`) values('javaEE20170325');
insert into t_clazz(`name`) values('javaEE20170420');
insert into t_clazz(`name`) values('javaEE20170515');

## 創建學生表
create table t_student(
	`id` int primary key auto_increment,
	`name` varchar(50),
	`clazz_id` int,
	foreign key(`clazz_id`) references t_clazz(`id`)
);

## 插入班級信息
insert into t_student(`name`,`clazz_id`) values('stu0228_1',1);
insert into t_student(`name`,`clazz_id`) values('stu0228_2',1);
insert into t_student(`name`,`clazz_id`) values('stu0228_3',1);
insert into t_student(`name`,`clazz_id`) values('stu0325_1',2);
insert into t_student(`name`,`clazz_id`) values('stu0325_2',2);
insert into t_student(`name`,`clazz_id`) values('stu0420_1',3);

2、<collection/> 一對多,立即加載

public class Student { private Integer id; private String name;
public class Clazz {
	private Integer id;
	private String name;
	private List<Student> stus;

ClazzMapper接口的代碼:

public interface ClazzMapper { // 一次全部查詢出來 public Clazz queryClazzByIdForSimple(Integer id); }

ClazzMapper配置信息:

<resultMap type="com.webcode.pojo.Clazz" id="queryClazzByIdForSimple_resultMap">
		<id column="id" property="id"/>
		<result column="name" property="name"/>
		<!-- 
			collection標簽用來映射子集合=====>>>>private List<Student> stus;
				property屬性你要映射哪個屬性
				ofType屬性配置集合中每個元素的具體類型
		 -->
		<collection property="stus" ofType="com.webcode.pojo.Student">
			<!-- id標簽用來配置主鍵列,可以去重 -->
			<id column="stu_id" property="id"/>
			<result column="stu_name" property="name"/>
		</collection>
	</resultMap>
<!-- 	public Clazz queryClazzByIdForSimple(Integer id); -->
	<select id="queryClazzByIdForSimple" resultMap="queryClazzByIdForSimple_resultMap">
		select 
			t_clazz.*,t_student.id stu_id,t_student.name stu_name,t_student.clazz_id
		from 
			t_clazz left join t_student
		on 
			t_clazz.id = t_student.clazz_id
		where 
			t_clazz.id = #{id}
	</select>

3、一對多,分步查詢賴加載

ClazzMapper接口方法:

public interface ClazzMapper { // 分兩次查,這邊只查班級 public Clazz queryClazzByIdForTwoStep(Integer id); }

StudentMapper接口方法:

public interface StudentMapper {
	// 只查學生,
	public List<Student> queryStudentByClazzId(Integer clazzId); }

StudentMaper的配置內容:

<!-- public List<Student> queryStudentByClazzId(Integer clazzId); --> <select id="queryStudentByClazzId" resultType="com.webcode.pojo.Student"> select id,name from t_student where clazz_id = #{clazzId} </select>

ClazzMapper的配置內容:

<resultMap type="com.webcode.pojo.Clazz" id="queryClazzByIdForTwoStep_resultMap"> <id column="id" property="id"/> <result column="name" property="name"/> <!-- collection映射子的集合屬性 property="stus" 設置當前要配置(封裝)哪個集合 select屬性配置使用哪個查詢得到這個集合 column屬性將某個列做為查詢語句的參數使用 --> <collection property="stus" column="id" select="com.webcode.mapper.StudentMapper.queryStudentByClazzId"/> </resultMap> <!-- public Clazz queryClazzByIdForTwoStep(Integer id); --> <select id="queryClazzByIdForTwoStep" resultMap="queryClazzByIdForTwoStep_resultMap"> select id,name from t_clazz where id = #{id} </select>

4、雙向關聯

StudentMapper接口

public interface StudentMapper { // 按班級id查學生。還可以關聯查班級 public List<Student> queryStudentsByClazzIdForTwoStep(Integer clazzId); }

StudentMapper的配置:

<resultMap type="com.webcode.pojo.Student" id="queryStudentsByClazzIdForTwoStep_resultMap"> <id column="id" property="id"/> <result column="name" property="name"/> <!-- association用來處理子對象 property屬性配置要處理哪個子對象 select屬性配置用哪個查詢得到這個子對象 column屬性將哪個列做為查詢的參數使用 --> <association property="clazz" column="clazz_id" select="com.webcode.mapper.ClazzMapper.queryClazzByIdForTwoStep"/> </resultMap> <!-- public List<Student> queryStudentsByClazzIdForTwoStep(Integer clazzId); --> <select id="queryStudentsByClazzIdForTwoStep" resultMap="queryStudentsByClazzIdForTwoStep_resultMap"> select id,name,clazz_id from t_student where clazz_id = #{clazzId} </select>

ClazzMapper的配置信息修改:

<resultMap type="com.webcode.pojo.Clazz" id="queryClazzByIdForTwoStep_resultMap"> <id column="id" property="id"/> <result column="name" property="name"/> <!-- collection映射子的集合屬性 property="stus" 設置當前要配置(封裝)哪個集合 select屬性配置使用哪個查詢得到這個集合 column屬性將某個列做為查詢語句的參數使用 --> <collection property="stus" column="id" select="com.webcode.mapper.StudentMapper.queryStudentsByClazzIdForTwoStep"/> </resultMap> <!-- public Clazz queryClazzByIdForTwoStep(Integer id); --> <select id="queryClazzByIdForTwoStep" resultMap="queryClazzByIdForTwoStep_resultMap"> select id,name from t_clazz where id = #{id} </select>

測試:

        @Test public void testQueryClazzByIdForTwoStep() { SqlSession session = sqlSessionFactory.openSession(); try { ClazzMapper mapper = session.getMapper(ClazzMapper.class); Clazz clazz = mapper.queryClazzByIdForTwoStep(1); session.clearCache();//清緩存,可以看到后面再次關聯班級時的查詢 System.out.println(clazz.getName()); List<Student> stus = clazz.getStus(); for (Student student : stus) { session.clearCache();//清緩存,可以看到后面再次關聯班級時的查詢 System.out.println( "學生姓名:" + student.getName() ); System.out.println( "學生所在班級名稱:" + student.getClazz().getName() ); } } catch (Exception e) { e.printStackTrace(); } finally { session.close(); } }

注意:雙向關聯常見問題,就是死循環:

解決方法一:不要調用任何一方的toString方法

解決方法二:最后一次的查詢使用resultType,而不是使用ResultMap


免責聲明!

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



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