MyBatis的使用
MyBatis常用的三个查询方法
selectList
用于查询多条数据,返回值是一个List集合。若没有查到任何数据返回一个空集合,不是null。
selectOne
用于查询单条数据,返回值是一个对象。如果没有查到任何数据,返回null。
selectMap
用于查询多条数据,返回值是一个Map集合。若没有查到任何数据返回一个空集合,不是null。
MyBatis的使用步骤
-
加载MyBatis.xml
InputStream is = Resources.getResourceAsStream("mybatis.xml");
-
获取SqlSessionFactory工厂对象
SqlSessionFactoryBuilder().build(is)会对xml进行解析
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
-
通过SqlSessionFactory工厂对象打开SqlSession
SqlSession session = factory.openSession();
-
执行查询操作
List<User> list = session.selectList(mapper);
-
关闭SqlSession
session.close();
static void selectAll() throws IOException {
//加载资源
InputStream is = Resources.getResourceAsStream("mybatis-cfg.xml");
//工厂对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
//Session
SqlSession session = factory.openSession();
//执行select: 命名空间+id
List<User> list = session.selectList("com.trf.mapper.UserMapper.selAll");
for (User user : list) {
System.out.println(user);
}
//关闭SqlSession
session.close();
}
SQL参数传递
#{}使用参数
index 从0开始
param+数字:param1,param2
<select id="selById" resultType="User" parameterType="int">
SELECT * FROM t_USER WHERE id = #{0}
</select>
DML操作
事务
-
事务是数据库操作的最小单元,有ACID的特性。应该保证一个事务中的SQL语句要么都成功,要么都不成功
-
MyBatis中配置了事务管理器,type属性设置为JDBC。表示使用原生JDBC相同的事务管理机制。
-
在MyBatis执行的开始时,将自动提交功能关闭。所以执行DML操作时,需要手动提交事务
新增
手动提交事务
public class TestInsert {
public static void main(String[] args) {
SqlSession session = MyBatisUtil.getSession();
User u = new User();
u.setUsername("谷七壮");
u.setPassword("123456");
int num = session.insert("com.trf.mapper.UserMapper.insUser", u);
if (num > 0) {
session.commit();
System.out.println("新增成功");
} else {
session.rollback();
System.out.println("新增失败");
}
session.close();
}
}
xml
<insert id="insUser" parameterType="user">
INSERT INTO T_USER VALUES(default, #{username}, #{password})
</insert>
可以使用factory.openSession(true)设置自动提交事务,不建议使用自动提交事务。
删和改
删
public static void testDel() {
SqlSession session = MyBatisUtil.getSession();
int num = session.delete("com.trf.mapper.UserMapper.delUser", 9);
if (num > 0) {
session.commit();
System.out.println("删除成功");
} else {
session.rollback();
System.out.println("删除失败");
}
session.close();
}
改
public static void testUpdate() {
SqlSession session = MyBatisUtil.getSession();
User u = new User();
u.setId(9);
u.setUsername("车七强");
u.setPassword("123456");
int num = session.update("com.trf.mapper.UserMapper.updUser", u);
if (num > 0) {
session.commit();
System.out.println("更新成功");
} else {
session.rollback();
System.out.println("更新失败");
}
session.close();
}
接口绑定方案
MyBatis中,提供了一套接口方案。程序员可以提供一个接口,然后提供对应接口的一个mapper.xml文件。
MyBatis会自动将对应接口的一个mapper.xml文件。MyBatis会自动将接口和xml文件进行绑定。实际上就是MyBatis会根据接口和对应的xml文件创建接口的实现类。也就是说可以得到接口类型的对象,方便方法的调用。
要点
- xml 文件名要和接口名一致
- 配置文件中的命名空间要和接口名一致
- id和和接口中的方法名一致
当需要扫描多个接口时,可以使用package标签,扫描包下的所有接口
接口
import java.util.List;
import com.trf.pojo.User;
public interface UserMapper {
/**
* 查询所有用户信息
* @return
*/
List<User> selAll();
}
配置文件
<?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="com.trf.mapper.UserMapper">
<select id="selAll" resultType="User">
SELECT * FROM t_user
</select>
</mapper>
测试
public class TestBind {
public static void main(String[] args) {
SqlSession session = MyBatisUtil.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
List<User> list = mapper.selAll();
for (User user : list) {
System.out.println(user);
}
session.close();
}
}
动态SQL
根据条件的不同, SQL 语句也会随之动态的改变. MyBatis 中,
提供了一组标签用于实现动态 SQL.
if标签和where标签
if标签,用于进行条件判断, test 属性用于指定判断条件. 为了拼接
条件, 在 SQL 语句后强行添加 1=1 的恒成立条件。
where标签用于管理 where 子句. 有如下功能:
- 如果没有条件, 不会生成 where 关键字
- 如果有条件, 会自动添加 where 关键字
- 去除第一个条件中的and
<select id="selByCondition" resultType="User">
SELECT * FROM t_user
<where>
<!-- if用于条件判断
test属性用于设定判断条件
-->
<if test="username != null and username != ''">
AND username = #{username}
</if>
<if test="password != null and password != ''">
AND password = #{password}
</if>
</where>
</select>
chose when otherwise标签组合
作用类似于switch case
<select id="selByCondition2" resultType="User">
SELECT * FROM t_user
<where>
<choose>
<when test="username != null and username != ''">
AND username = #{username}
</when>
<when test="password != null and password != ''">
AND password = #{password}
</when>
<otherwise>
AND 1 = 1
</otherwise>
</choose>
</where>
</select>
set标签
用于维护 update 语句中的 set 子句. 功能如下:
- 满足条件时, 会自动添加 set 关键字
- 会去除 set 子句中多余的逗号
- 不满足条件时, 不会生成 set 关键字
<update id="updUser" parameterType="user">
UPDATE t_user
<set>
id = #{id}
<if test="username != null and username != ''">
username = #{username},
</if>
<if test="password != null and password != ''">
password = #{password},
</if>
</set>
WHERE id = #{id}
</update>
foreach标签
用来迭代一个集合,通常用来构建IN条件。
<select id="selIn" parameterType="list" resultType="user">
SELECT * FROM t_user
<where>
id in
<!-- 遍历list集合,取了到item,以'('开始,','分隔',以')'结束 -->
<foreach collection="list" item="item" open="(" separator = "," close = ")">
#{item}
</foreach>
</where>
</select>
include标签
引用写好的sql
<sql id="mySql">
id, username, password
</sql>
<select id="selAll" resultType="User">
SELECT <include refid="mySql"/> FROM t_user
</select>
MyBaties的缓存机制
缓存机制,提高查询效率
Mybatis支技缓存,有两种缓存机制
一级缓存
线程级别的缓存,SqlSession对象缓存。
默认开启。
基于SQL的id,id不一样语句一样也不会触发缓存查询。
同 一个SqlSession对象同一个id才可以使用。
二级缓存
进程级别的缓存,SqlSessionFactory对象缓存。
在mapper配置 文件中,使用cache标签开启。
列名和属性名不一致
如果查询时使用 resultType 属性, 表示采用 MyBatis 的Auto-Mapping(自动映射)机制, 即相同的列名和属性名会自
动匹配. 因此, 当数据库表的列名和类的属性名不一致时, 会导致查不到数据. 解决该问题可以有两种方式:
1. 列别名
查询时, 可以通过列别名的方式将列名和属性名保持一致, 继续使用自动映射, 从而解决该问题. 但是较为麻烦.
2. ResultMap
用于自定义映射关系, 可以由程序员自主制定列名和属性名的映射关系. 一旦使用 resultMap, 表示不再采用自动映射机制.
<resultMap type="user" id="umap">
<!-- 映射主键 -->
<id column="id" property="id1"/>
<!-- 映射非主键 -->
<result column="username" property="username1"/>
<result column="password" property="password1"/>
</resultMap>
<select id="selAll" resultMap="umap">
SELECT * FROM t_user
</select>
多表关联查询
学生表(t_student),字段 :id, name, age, gender, cid
班级表(t_class),字段:id, name, room
业务装配
在service 业务层通过组装mapper 层的单表查询的结果返回结果集合。
实体类
创建班级类(Clazz)和学生类(Student), 并在 Student 中添加一个 Clazz 类型的属性, 用于表示学生的班级信息。
mapper 层
提供StudentMapper和ClazzMapper, StudentMapper查询所有学生信息, ClazzMapper 根据编号查询班级信息.
<mapper namespace="com.trf.mapper.StudentMapper">
<select id="selAll" resultType="student">
SELECT * FROM t_student
</select>
</mapper>
<mapper namespace="com.trf.mapper.ClazzMapper">
<select id="selById" resultType="clazz" parameterType="int">
SELECT * FROM t_class WHERE id = #{0};
</select>
</mapper>
service 层
public class StudentServiceImpl implements StudentService {
@Override
public List<Student> selAll() {
SqlSession session = MyBatisUtil.getSession();
StudentMapper stuMapper = session.getMapper(StudentMapper.class);
List<Student> stuList = stuMapper.selAll();
//为每个Student对象组装Clazz信息
for (Student s : stuList) {
ClazzMapper clzMapper = session.getMapper(ClazzMapper.class);
s.setClazz(clzMapper.selById(s.getCid()));
}
session.close();
return stuList;
}
}
测试
public class TestSel {
public static void main(String[] args) {
StudentService ss = new StudentServiceImpl();
List<Student> list = ss.selAll();
for (Student student : list) {
System.out.println(student);
}
}
}
resultMap的N+1方式实现多表查询
mapper 层
提供StudentMapper和ClazzMapper, StudentMapper查询所有学生信息, ClazzMapper 根据编号查询班级信息. 在StudentMapper 中使用设置装配.
- property: 指定要关联的属性名
- select: 设定要继续引用的查询, namespace+id
- column: 查询时需要传递的列
<mapper namespace="com.trf.mapper.StudentMapper">
<resultMap type="student" id="smap">
<result column="cid" property="cid"/>
<!-- 关联对象 -->
<association property="clazz" column="cid" select="com.trf.mapper.ClazzMapper.selById"></association>
</resultMap>
<select id="selAll" resultMap="smap">
SELECT * FROM t_student
</select>
</mapper>
<mapper namespace="com.trf.mapper.ClazzMapper">
<select id="selById" resultType="clazz" parameterType="int">
SELECT * FROM t_class WHERE id = #{0};
</select>
</mapper>
service 层
由于装配已经完成, service 层只需要调用 mapper 即可, 不需要再进行装配了.
public class StudentServiceImpl implements StudentService {
@Override
public List<Student> selAll() {
SqlSession session = MyBatisUtil.getSession();
StudentMapper stuMapper = session.getMapper(StudentMapper.class);
List<Student> stuList = stuMapper.selAll();
session.close();
return stuList;
}
}
resultMap 的关联方式实现多表查询(
mapper 层
- 在 StudentMapper.xml 中定义多表连接查询 SQL 语句, 一次性查到需要的所有数据, 包括对应班级的信息.
- 通过定义映射关系, 并通过指
定对象属性的映射关系. 可以把看成一个使用. javaType 属性表示当前对象, 可以写全限定路径或别名.
<mapper namespace="com.trf.mapper.StudentMapper">
<resultMap type="student" id="smap">
<id column="sid" property="id"/>
<result column="sname" property="name"/>
<result column="age" property="age"/>
<result column="cid" property="cid"/>
<result column="sname" property="name"/>
<association property="clazz" javaType="clazz">
<id column="cid" property="id"/>
<result column="cname" property="name"/>
<result column="room" property="room"/>
</association>
</resultMap>
<select id="selAll" resultMap="smap">
SELECT s.id sid, s.`name` sname, s.age, s.gender, c.id cid, c.`name` cname, c.room
FROM t_student s, t_class c
WHERE s.cid = c.id
ORDER BY s.id
</select>
</mapper>
service层
本层不用修改。