MyBatis使用详解

  • 什么是MyBatis?

MyBatis是一个基于Java的数据库持久化层框架,它支持自定义 SQL、存储过程以及高级映射。它免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。 通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。MyBatis采用 ORM(Object-Relationl Mapping) 思想解决了实体和数据库映射的问题,对 JDBC进行了封装,屏蔽了 JDBC API 底层访问细节,使我 们不用与 JDBC API 打交道,就可以完成对数据库的持久化操作。

  • MyBatis中的主要组成部分

MyBatis中主要使用的类和接口有:SqlSessionFactoryBuilder、SqlSessionFactory和SqlSession。

  • SqlSessionFactoryBuilder(工厂构造器):

SqlSessionFactoryBuilder负责构建SqlSessionFactory 。它可以通过XML文件构建出SqlSessionFactory示例。它的最大特点是:用过即丢。一旦创建了SqlSessionFactory 对象之后,这个类就不需要存在了,因此SqlSessionFactoryBuilder 只用存在于方法体内方法调用后就可以销毁,也就是局部变量。

  • SqlSessionFactoryr(SqlSession工厂):

SqlSessionFactory的作用就是通过openSession()方法创建出一个个的SqlSession实例。所以SqlSessionFactory实例一旦创建就伴随着整个程序的生命周期,而且在整个程序生命周期中只需要创建一个SqlSession实例即可。

SqlSessionFactory创建代码示例:
private static final String CONFIG = "mybatis-config.xml"; //配置文件
	private static SqlSessionFactory sqlSessionFactory; //SqlSessionFactory对象
	private static final Class<MyBatisUtils> CLASS_LOCK = MyBatisUtils.class; //类级别锁
	
	private static SqlSessionFactory initSqlSessionFactory() {
		if (sqlSessionFactory == null) {
			synchronized (CLASS_LOCK) {  //添加类级别同步锁保证线程安全
	            // 读取配置文件
				try (InputStream inputStream = Resources.getResourceAsStream(CONFIG)) {
	                // SqlSessionFactoryBuilder通过读取到配置文件创建SqlSessionFactory
					sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
				} catch (IOException e) {
					e.printStackTrace();
				}
  		}
  	}
  	return sqlSessionFactory;
  }
  • SqlSession(会话):

SqlSession 是用于持久化操作的对象,类似于 JDBC 操作中的Connection 。它提供了在数据库执行 SQL 命令所需的所有方法,可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。SqlSession 的实例不是线程安全的,因此不能被共享,在每次使用都要确保它能够被关闭。

SqlSession创建代码示例:
  public static SqlSession openSqlSession() {
 	if (sqlSessionFactory == null) {
 		initSqlSessionFactory();
 	}
     // 调用sqlSessionFactory的openSession()方法创建出SqlSession实例
 	return sqlSessionFactory.openSession();
 }
  • MyBatis (mybatis-config.xml) 配置

  • 设置(settings)

主要作用:对MyBatis运行时的行为进行设置。如MyBatis缓存、日志的开启和关闭等。

设置(settings)代码示例:
<!-- MyBatis配置 -->
	<settings>	
		<!-- 开启日志 -->
		<setting name="logImpl" value="STDOUT_LOGGING"/>
	</settings>
  • 类型别名(typeAliases)

主要作用:类型别名可为 Java 类型设置一个缩写名字,也可以指定一个实体类的包名,MyBatis 会在包名下面搜索需要的 Java Bean。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。

类型别名(typeAliases)代码示例:
<!-- 为实体类设置别名 -->
<typeAliases>
 <!-- 为每一个实体类设置别名
		type:实体类的完全限定名
		alias:实体类别名 
   <typeAlias type="com.apesource.entity.AnswerRecord" alias="AnswerRecord"/> 
 -->
  <!-- 设置实体类包,为package中的每一个实体类自动设置别名(别名为首字母小写的非限定类名) -->
	<package name="com.apesource.entity"/>
</typeAliases>
  • 环境配置(environments)

主要作用:MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中, 现实情况下有很多情况下需要使用不同的环境。例如,开发、测试和生产环境需要有不同的配置;或者想在具有相同 Schema 的多个生产数据库中使用相同的 SQL 映射。虽然可以配置多个不同的环境,但是每次只能选择使用其中的一个环境进行使用。

环境配置(environments)代码示例:
<!-- 指定使用环境为development -->
<environments default="development">
   	<!-- 配置一个环境id为环境“名称” -->
		<environment id="development">
           <!-- 事务管理器的配置  -->
			<transactionManager type="JDBC" />
           <!-- 数据源的配置 -->
			<dataSource type="POOLED">
               <!-- 这是 JDBC 驱动的 Java 类全限定名 -->
				<property name="driver" value="${jdbc_driver}" />
               <!-- 这是数据库的 JDBC URL 地址 -->
				<property name="url" value="${jdbc_url}" />
               <!-- 登录数据库的用户名 -->
				<property name="username" value="${db_username}" />
                <!-- 登录数据库的密码 -->
				<property name="password" value="${db_password}" />
			</dataSource>
		</environment>
	</environments>
  • 映射器(mappers)

主要作用:告诉 MyBatis 到哪里去找到SQL映射语句。 在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找SQL映射文件。

映射器(mappers)代码示例:
<!-- 指定SQL映射文件的位置 -->
<mappers>
	<mapper resource="com/apesource/dao/mapper/AnswerRecordMapper.xml"/>
</mappers>
  • MyBatis XML 映射器

1.常用节点作用总结

  • select :映射一个select数据查询SQL语句。
  • update:映射一个update数据更新SQL语句。
  • delete:映射一个delete数据删除SQL语句。
  • insert: 映射一个insert数据插入SQL语句。

2.常用属性作用总结

  • id 属性: 为当前映射的SQL语句进行命名。
  • resultType 属性: 设置查询结果使用的类型名称。
  • parameterType 属性:设置SQL操作时使用的实体类(别名)。
  • useGeneratedKeys属性: 开启主键回填。
  • keyProperty属性: 指定返回的主键值应该被实体类的哪一个属性接收。

3.常见SQL映射示例

示例1:普通增加

SQL映射配置
<!-- 添加新答题记录 -->
<insert id="insertAnswerRecord" 
parameterType="AnswerRecord"
useGeneratedKeys="true"
keyProperty="recordId">
insert into answer_record 	                     (respondent,question,right_answer,submit_answer,submit_datetime)
values(#{respondent},#{question},#{rightAnswer},#{submitAnswer},now())
</insert>
接口方法定义
 /**
 * 添加新答题记录
 * @param answerRecord 答题记录对象
 * @return 影响行数
 * ps.测试时需要输出新答题记录的编号
 */
int insertAnswerRecord(AnswerRecord answerRecord);
具体方法实现
// 添加新答题记录,测试时返回主键
public int insertAnswerRecordMethod(AnswerRecord answerRecord) {
	// 保证sqlSession在使用完成后关闭
	try(SqlSession sqlSession = MyBatisUtils.openSqlSession()) {
		AnswerRecordMapper answerRecordMapper =sqlSession.getMapper(AnswerRecordMapper.class);
		int rows = answerRecordMapper.insertAnswerRecord(answerRecord);
		sqlSession.commit();//提交事务
		return rows;
	} catch (Exception e) {
		e.printStackTrace();
		return -1;
	}
}

示例2:批量增加

SQL映射配置
<!-- 批量添加新答题记录 -->
<insert id="insertAnswerRecordBatch" 
parameterType="list"
useGeneratedKeys="true"
keyProperty="recordId">
insert into answer_record
(respondent,question,right_answer,submit_answer,submit_datetime)
values
<!-- foreach:循环遍历,其中collection是指明需要遍历的集合类型,item给遍历出来的一个元素起别名,separator指明遍历出来的每个元素用什么分隔开 -->
	<foreach collection="list" item="record" separator=",">
		(#{record.respondent},#{record.question},#{record.rightAnswer},					#{record.submitAnswer},now())
	</foreach>
</insert>

接口方法定义
/**
 * 批量添加新答题记录
 * @param answerRecordList 添加数据集合
 * @return 影响行数
*/
int insertAnswerRecordBatch(List<AnswerRecord> answerRecordList);
具体方法实现
// 批量添加新答题记录,测试时返回主键
public int insertAnswerRecordBatchMethod(List<AnswerRecord> answerRecordList) {
	// 保证sqlSession在使用完成后关闭
	try(SqlSession sqlSession = MyBatisUtils.openSqlSession()) {
		AnswerRecordMapper answerRecordMapper =sqlSession.getMapper(AnswerRecordMapper.class);
		int rows = answerRecordMapper.insertAnswerRecordBatch(answerRecordList);
		sqlSession.commit();//提交事务
		return rows;
	} catch (Exception e) {
		e.printStackTrace();
		return -1;
	}
}

示例3:普通删除

SQL映射配置
<!-- 删除答题记录 -->
<delete id="deleteAnswerRecord">
	delete from answer_record where record_id=#{recordId}
</delete>
接口方法定义
>/**
* 删除答题记录
* @param recordId 答题记录编号
* @return 影响行数
*/
int deleteAnswerRecord(int recordId);
具体方法实现	
//删除一条答题记录
public int deleteAnswerRecordMethod(int recordId) {
// 保证sqlSession在使用完成后关闭
try(SqlSession sqlSession = MyBatisUtils.openSqlSession()) {
		AnswerRecordMapper answerRecordMapper =sqlSession.getMapper(AnswerRecordMapper.class);
		int rows = answerRecordMapper.deleteAnswerRecord(recordId);
		sqlSession.commit();//提交事务
		return rows;
	} catch (Exception e) {
		e.printStackTrace();
		return -1;
	}
}

示例4:批量删除

SQL映射配置
<!-- 批量删除记录 -->
<delete id="deleteAnswerRecordBatch"
parameterType="list">
delete from answer_record where record_id in
<foreach collection="list"
      item="recordId"
       open="(" close=")"
       separator=",">
  #{recordId}
</foreach>
</delete>
接口方法定义
/**
* 批量删除答题记录
* @param recordIdList
* @return
*/
int deleteAnswerRecordBatch(List<Integer> recordIdList);
具体方法实现	
//批量删除
public int deleteAnswerRecordBatchMethod(List<Integer> recordIdList) {
// 保证sqlSession在使用完成后关闭
try(SqlSession sqlSession = MyBatisUtils.openSqlSession()) {
	AnswerRecordMapper answerRecordMapper =sqlSession.getMapper(AnswerRecordMapper.class);
	int rows = answerRecordMapper.deleteAnswerRecordBatch(recordIdList);
	sqlSession.commit();//提交事务
	return rows;
} catch (Exception e) {
	e.printStackTrace();
	return -1;
}
}

示例5:动态修改

SQL映射配置
<!-- 修改答题记录 -->
<update id="updateAnswerRecord" 
parameterType="AnswerRecord">
<!-- set节点用于动态处理update中的set   if用于处理传入的条件判断存入为空则不修改 -->
update answer_record 
<set>
<if test="respondent != null">respondent = #{respondent},</if>
<if test="question != null">question = #{question},</if>
<if test="rightAnswer != null">right_answer = #{rightAnswer},</if>
<if test="submitAnswer != null">submit_answer = #{submitAnswer},</if>
submit_datetime = now()
</set>
where record_id = #{recordId}
</update>
接口方法定义
/**
 * 动态修改答题记录
   * @param answerRecord 答题记录对象(包含答题记录编号)
   * @return 影响行数
*/
int updateAnswerRecord(AnswerRecord answerRecord); 
具体方法实现	
//修改答题记录
public int updateAnswerRecordMethod(AnswerRecord answerRecord) {
// 保证sqlSession在使用完成后关闭
try(SqlSession sqlSession = MyBatisUtils.openSqlSession()) {
	AnswerRecordMapper answerRecordMapper =sqlSession.getMapper(AnswerRecordMapper.class);
	int rows = answerRecordMapper.updateAnswerRecord(answerRecord);
	sqlSession.commit();//提交事务
	return rows;
} catch (Exception e) {
	e.printStackTrace();
	return -1;
}
}

示例6:动态查询

SQL映射配置
<!-- 按照条件对象中的多条件值,动态查询 -->
<select id="listAnswerRecordByCondition" 
resultType="AnswerRecord" 
parameterType="AnswerRecord"> 
select record_id as recordId,
		respondent as respondent,
		question as question,
		right_answer as rightAnswer,
		submit_answer as submitAnswer,
		submit_datetime as submitDatetime
from answer_record 
<!-- 通过使用where节点来替代原来SQL语句中的where关键字配合if节点实现动态查询 -->
<where>
	 <if test="respondent != null">and respondent = #>>{respondent}</if>
	<if test="question != null">and question like concat('%', #{question},'%')</if>
	<if test="rightAnswer != null">and right_answer = #{rightAnswer}</if>
	<if test="submitAnswer != null">and submit_answer = #{submitAnswer}</if>
</where>
</select>
接口方法定义
/**
* 按照条件对象中的多条件值,动态查询
* @param condition 条件对象
* @return 答题记录集合
*/
List<AnswerRecord> listAnswerRecordByCondition(AnswerRecord condition);
具体方法实现	
// 按照条件对象中的多条件值,动态查询
public List<AnswerRecord> listAnswerRecordByConditionMethod(AnswerRecord condition){
// 保证sqlSession在使用完成后关闭
try(SqlSession sqlSession = MyBatisUtils.openSqlSession()) {
	AnswerRecordMapper answerRecordMapper =sqlSession.getMapper(AnswerRecordMapper.class);
	List<AnswerRecord> listAnswerRecords = answerRecordMapper.listAnswerRecordByCondition(condition);
	return listAnswerRecords;
} catch (Exception e) {
	e.printStackTrace();
	return Arrays.asList();
}
}

示例7:查询结果封装为Map

SQL映射配置
<!-- 按照答题者姓名,统计该答题者的总答题数目、正确题目数目、错误题目数目 -->
<select id="countAnswerRecordDataByRespondent" 
	resultType="map">
SELECT COUNT(record_id) as sum_answer,
(SELECT COUNT(record_id) FROM answer_record WHERE right_answer = submit_answer     AND respondent = #{respondent}) as sum_true,(SELECT COUNT(record_id) FROM         answer_record WHERE right_answer != submit_answer AND respondent = #               {respondent}) as sum_falseFROM answer_record WHERE respondent = #{respondent}
</select>
接口方法定义
/**
* 按照答题者姓名,统计该答题者的总答题数目、正确题目数目、错误题目数目
* @param respondent
* @return
*/
Map<String,Integer> countAnswerRecordDataByRespondent(String respondent);
具体方法实现
//按照答题者姓名,统计该答题者的总答题数目、正确题目数目、错误题目数目
public Map<String,Integer> countAnswerRecordDataByRespondentMethod(String respondent){
t// 保证sqlSession在使用完成后关闭
try(SqlSession sqlSession = MyBatisUtils.openSqlSession()) {
AnswerRecordMapper answerRecordMapper =sqlSession.getMapper(AnswerRecordMapper.class);
Map<String,Integer> mapAnswerRecordDataByRespondent = answerRecordMapper.countAnswerRecordDataByRespondent(respondent);
return mapAnswerRecordDataByRespondent;
} catch (Exception e) {
	e.printStackTrace();
	return new HashMap<String,Integer>();
}
}
  • 附录

MyBatis 更多属性和设置可参见mybatis-MyBatis 3| 配置

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值