<?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">
<mapper namespace="main.dao.StudentMapper">
<select id="getJustStudentInfo" resultType="EStudent">
select ID,Name from TStudentML where Name = #{0}
</select>
<select id="getJustStudentInfos" resultType="EStudent">
select * from TStudentML
<if test="#{0} != null">
where name like '%'+#{0}+'%'
</if>
</select>
<select id="getStudentInfo" resultMap="getStudentInfoResultMap">
select
a.ID a_id, a.Name a_name,
b.ID b_id, b.Name b_name,
c.ID c_id, c.Name c_name, c.ClassID c_classId
from
TStudentML a left outer join TClassML b on(a.ClassID=b.ID)
left outer join TTeacherML c on(b.ID=c.ClassID)
<trim prefix="where" prefixOverrides="and">
<if test="#{0} != null">
a.Name like '%'+#{0}+'%'
</if>
<if test="#{1} != null">
and b.Name like '%'+#{1}+'%'
/if>
</trim>
</select>
<resultMap id="getStudentInfoResultMap" type="EStudent">
<id property="id" column="a_id"/>
<result property="name" column="a_name"/>
<!-- 一对一关系 -->
<association property="myClass" javaType="EClass">
<id property="id" column="b_id"/>
<result property="name" column="b_name"/>
</association>
<!-- 一对多关系 -->
<collection property="teachers" ofType="ETeacher">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<result property="classId" column="c_classId"/>
</collection>
</resultMap>
<insert id="addStudent" parameterType="EStudent">
insert into TStudentML(Name, ClassID) values(#{name}, #{myClass.id})
</insert>
<delete id="delStudent">
delete from TStudentML where ID = #{0}
</delete>
</mapper>
9. 数据库操作基类
public class DBase{
private static SqlSessionFactory factory = null;
public DBase(){
if (factory != null) return;
InputStream is = this.getClass().getClassLoader().getResourceAsStream("mybatis-config.xml");
factory = new SqlSessionFactoryBuilder().build(is);
}
/**
* 获取SqlSession实例,使用后需调用实例的close()函数释放资源
* @return
*/
protected SqlSession openSession(){
return factory.openSession();
}
}
10. 数据库操作类
public class DStudent extends DBase{
/**
* 通过姓名获取学生信息(不含教师、班级信息)
* @param name 学生姓名
* @return
*/
public EStudent getJustStudentInfo(String name){
EStudent ret = null;
SqlSession session = openSession();
try{
StudentMapper sm = session.getMapper(StudentMapper.class);
ret = sm.getJustStudentInfo(name);
}
finally{
session.close();
}
return ret;
}
/**
* 通过姓名模糊查询学生信息(不含教师、班级信息)
* @param name 学生姓名
* @return
*/
public List<EStudent> getJustStudentInfos(String name){
List<EStudent> ret = null;
SqlSession session = openSession();
try{
StudentMapper sm = session.getMapper(StudentMapper.class);
ret = sm.getJustStudentInfos(name);
}
finally{
session.close();
}
return ret;
}
/**
* 通过姓名和班级名称获取学生信息(含教师、班级信息)
* @param name 学生姓名
* @param className 班级名称
* @return
*/
public EStudent getStudentInfo(String name, String className){
EStudent ret = null;
SqlSession session = openSession();
try{
StudentMapper sm = session.getMapper(StudentMapper.class);
ret = sm.getStudentInfo(name, className);
}
finally{
session.close();
}
return ret;
}
/**
* 新增学生信息
* @param student
*/
public void addStudent(EStudent student){
SqlSession session = openSession();
try{
StudentMapper sm = session.getMapper(StudentMapper.class);
sm.addStudent(student);
session.commit();
}
finally{
session.close();
}
}
/**
* 删除学生信息
* @param id
*/
public void delStudent(int id){
SqlSession session = openSession();
try{
StudentMapper sm = session.getMapper(StudentMapper.class);
sm.delStudent(id);
session.commit();
}
finally{
session.close();
}
}
}
三、基础知识
作为一个ORM框架,可以知道其至少由对象模型转换为关系模型、关系模型转换为对象模型和缓存管理这三个模块组成。
MyBatis在对象模型转换为关系模型模块的实现方式是对象模型实例属性+自定义SQL语句,好处是对SQL语句的可操作性高,同时简化SQL入参的处理;坏处是对于简单的单表操作,依旧要写SQL语句,无法由对象模型自动生成SQL,最明显的问题是在开发初期数据表结构不稳定,一旦表结构改了,代码上不仅要改对象模型还要改SQL语句(不过MyBatis也考虑到这点,通过<sql>标签实现SQL语句复用,缓解这样问题)。
关系模型转换为对象模型则采用关系模型结果集字段映射到对象模型实体字段的方式处理。
缓存模块则分为SQL语句缓存和查询数据缓存两种,由于MyBatis需要开发者自定义SQL语句,因此SQL语句缓存不用考虑;而查询数据缓存则被分为一级和二级缓存,一级缓存以事务为作用域,二级缓存以同一个映射集为作用域,而且二级缓存采用直写的方式处理缓存数据被修改和删除的情况。
(本人不才,曾开发轻量级ORM框架LessSQL.Net,由于设计为SQL语句必须由对象模块实例映射生成,而关系模型数据集合无法自动填充任意的对象模型实体中,无法支撑复杂的查询语句,而缓存方面仅实现了SQL语句缓存性能优化有限,因此框架仅适用于小型工具软件。因为踩过这些坑,所以对ORM框架有一点浅薄的认识和看法)
言归正转,我们一起了解MyBatis的基础知识吧。 1. MyBatis框架配置文件
实际上就是MyBatis会话工厂的配置文件,用于配置如缓存、日志框架、数据库链接信息、两种模型间转换的处理器和注册映射集等。通过上文大家应该知道如何Make it work了。而Make it better也是从这里出发。 2. 映射集
映射集是由多个“标识”——“SQL语句”组成,映射记录上还有如入参类型、返回类型等信息,为对象关系模型转换引擎提供元数据。
设置映射集的方式有两种,一种是通过接口,一种通过xml文档。但上文示例采用两者相结合的方式,综合两者优点。 [a]. 映射接口方式
public interface StudentMapper{
@Select("select * from TStudentML where Name=#{0}")
EStudent getJustStudent(String name);
@Insert("insert into TStudentML(Name, ClassID) values(#{name}, #{myClass.id})")
void addStudent(EStudent student);
@Delete("delete from TStudentML where ID=#{0}")
void delStudent(int id);
@Update("update TStudentML set Name=#{name},ClassID=#{myClass.id} where ID=#{id}")
void updateStudent(EStudent student);
}
<if test="#{0} != null and #{1} != null">
and Name like '%'+#{0}+'%' and Description like '%'+#{1}+'%'
</if>
. <choose></choose>
相当于Java的switch语句。示例:
<choose>
<when test="#{title} !=null">
and Title = #{title}
</when>
<when test="#{name} !=null">
and Name = #{name}
</when>
<otherwise>
and Age > 10
</otherwise>
</choose>
[c]. <where></where>
用于处理动态条件时,where留存与否的尴尬。具体就是
select * from tbl
where
<if test="#{name}!=null">
Name = #{name}
</if>
<if test="#{title}!=null">
and Title = #{title}
</if>
当两个条件都不符合时,sql语句就变成 select * from tbl where ,报错是必然的。而 where标签 会根据其标签体是否有值来决定是否插入where关键字,并会自动去除无用的 or 和 and 关键字。示例:
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
<where>
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</where>
</select>
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>