事务管理
获取sqlSession时,默认开启事务,SqlSessionFactory类实例在调用openSession时不设置或者设置为false,此情况下,操作完成后,需要手动提交。
手动提交与回滚事务
public void insertStudent() {
// 会话链接
SqlSession sqlSession = MybatisUtil.getSqlSession();
int i = 0;
try {
// 实体对象
Student student = new Student(0, "00014", "wang14", "M", 29);
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
System.out.println(studentDao);
// 插入操作
i = studentDao.insertStudent(student);
sqlSession.commit();
} catch (Exception e) {
sqlSession.rollback();
}
Assert.assertEquals(1, i);
}
自动提交事务
获取sqlSession时,默认开启事务,SqlSessionFactory类实例在调用openSession时设置为true,此情况下,操作完成后,会自动提交。
// 会话工厂
SqlSessionFactory factory = builder.build(inputStream);
// 会话链接,设置为true,再执行操作后,自动执行sqlSession.commit()
SqlSession sqlSession = factory.openSession(true);
此情况知适用于只执行了增删改的一种操作,且只有一次操作的情况下,其他情况不建议使用自动提交。
mybatis的xml配置
需要遵循的顺序:
resultType和resultMap的区别:
resultType:指定当前sql返回数据封装的对象类型(实体类)
resultMap:指定从数据表到实体类的字段和属性的对应关系
分页查询
引入插件
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.2</version>
</dependency>
接口
public List<Student> selectStudentByGenderUsingPageHelper(String gender);
xml配置如下
<sql id="sutdentAll">sid,stu_num,stu_name,stu_gender,stu_age</sql>
<select id="selectStudentByGenderUsingPageHelper" resultMap="StudentMap">
select <include refid="sutdentAll" /> from tb_students where stu_gender=#{gender}
</select>
使用插件进行分页查询
public void selectStudentByGenderUsingPageHelper() {
StudentDao studentDao = MybatisUtil.getMapper(StudentDao.class);
PageHelper.startPage(1,4);
List<Student> students = studentDao.selectStudentByGenderUsingPageHelper("M");
PageInfo<Student> info = new PageInfo<Student>(students);
List<Student> list = info.getList();
for (Student s:list) {
System.out.println(s);
}
}
关联映射
实体关系:指的是数据与数据之间的关系
一对一关联:主键,唯一外键
一对多关联, 多对一关联:在多的一端添加外键,和一的一端关联
多对多关联:建立第三张关系表,添加两个外键,分别与两张表的主键进行关联
一对一关联
场景为查询用户的信息,信息放在两张表,通过名字查询所有的信息:
创建两张表
-- 用户基础信息表
CREATE TABLE users(
user_id INT PRIMARY KEY AUTO_INCREMENT,
user_name VARCHAR(20) NOT NULL UNIQUE,
user_pwd VARCHAR(20) NOT NULL,
user_realname VARCHAR(20) NOT NULL,
user_img VARCHAR(100) NOT NULL
);
-- 用户详情信息表
CREATE TABLE details(
detail_id INT PRIMARY KEY AUTO_INCREMENT,
user_addr VARCHAR(50) NOT NULL,
user_tel CHAR(20) NOT NULL,
user_desc VARCHAR(200),
uid INT NOT NULL UNIQUE
);
创建两个实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class User {
private int userId;
private String userName;
private String userPwd;
private String userRealName;
private String userImg;
private Detail detail;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Detail {
private int detailId;
private String userAddr;
private String userTel;
private String userDesc;
private int uId;
}
创建DAO接口
public interface UserDao {
public int insertUser(User user);
public User queryUser(String userName);
public User queryUserByInnerJoin(String userName);
public User queryUserByAssociation(String userName);
}
public interface DetailDao {
public int insertDetail(Detail detail);
public Detail queryDetail(int uId);
}
创建mapper文件
分别针对上述两个接口创建mapper文件,如下是UserDao对应的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">
<mapper namespace="com.kingyal.dao.UserDao">
<!-- 需要回填主键 -->
<insert id="insertUser" useGeneratedKeys="true" keyProperty="userId" timeout="3000" parameterType="User">
insert into users(user_name,user_pwd,user_realname,user_img)
values(#{userName},#{userPwd},#{userRealName},#{userImg});
</insert>
<resultMap id="userMap" type="User">
<id column="user_id" property="userId"></id>
<result column="user_name" property="userName"></result>
<result column="user_pwd" property="userPwd"></result>
<result column="user_realname" property="userRealName"></result>
<result column="user_img" property="userImg"></result>
<result column="detail_id" property="detail.detailId"></result>
<result column="user_addr" property="detail.userAddr"></result>
<result column="user_tel" property="detail.userTel"></result>
<result column="user_desc" property="detail.userDesc"></result>
<result column="uid" property="detail.uId"></result>
</resultMap>
<!-- association关联子查询; select:对应的查询方法; column:子查询的入参 -->
<resultMap id="userDetailMap" type="User">
<id column="user_id" property="userId"></id>
<result column="user_name" property="userName"></result>
<result column="user_pwd" property="userPwd"></result>
<result column="user_realname" property="userRealName"></result>
<result column="user_img" property="userImg"></result>
<association property="detail" select="com.kingyal.dao.DetailDao.queryDetail" column="user_id"></association>
</resultMap>
<select id="queryUser" resultMap="userMap">
select user_id,user_name,user_pwd,user_realname,user_img
from users where user_name=#{userName}
</select>
<select id="queryUserByInnerJoin" resultMap="userMap">
SELECT user_id,user_name,user_pwd,user_realname,user_img,detail_id,user_addr,user_tel,user_desc,uid
FROM users u
INNER JOIN details d
ON u.user_id=d.uid
WHERE u.user_name=#{userName}
</select>
<select id="queryUserByAssociation" resultMap="userDetailMap">
SELECT user_id,user_name,user_pwd,user_realname,user_img
FROM users u
WHERE u.user_name=#{userName}
</select>
</mapper>
如下是detailDao对应的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">
<mapper namespace="com.kingyal.dao.DetailDao">
<insert id="insertDetail" useGeneratedKeys="true" keyProperty="detailId" timeout="3000" parameterType="Detail">
insert into details(user_addr,user_tel,user_desc,uid)
values(#{userAddr},#{userTel},#{userDesc},#{uId});
</insert>
<resultMap id="detailMap" type="Detail">
<id column="detail_id" property="detailId"></id>
<result column="user_addr" property="userAddr"></result>
<result column="user_tel" property="userTel"></result>
<result column="user_desc" property="userDesc"></result>
<result column="uid" property="uId"></result>
</resultMap>
<select id="queryDetail" resultMap="detailMap">
select detail_id,user_addr,user_tel,user_desc,uid
from details where uId=${uId}
</select>
</mapper>
需要将上述两个xml文件加到mybatis的配置文件中:
给实体指定类名:
测试类
可重点关注queryUserByInnerJoin()和queryUserByAssociation(),他们分别通过连接查询的方式和子查询的方式实现users表到details表的一对一查询:
public class UserDaoTest {
@Test
public void insertUser() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
try {
User user = new User(0, "wangwu", "123456", "wangwu", "2.jpg", null);
Detail detail = new Detail(0, "shanghai", "18007777701", "my dream", 0);
UserDao userDao = sqlSession.getMapper(UserDao.class);
int i = userDao.insertUser(user);
Assert.assertEquals(1 ,i);
System.out.println(user);
detail.setUId(user.getUserId());
DetailDao detailDao = sqlSession.getMapper(DetailDao.class);
i = detailDao.insertDetail(detail);
Assert.assertEquals(1 ,i);
System.out.println(detail);
sqlSession.commit();
} catch (Exception e) {
sqlSession.rollback();
}
}
@Test
public void queryUser() {
UserDao userDao = MybatisUtil.getMapper(UserDao.class);
User user = userDao.queryUser("wangwu");
System.out.println(user);
DetailDao detailDao = MybatisUtil.getMapper(DetailDao.class);
Detail detail = detailDao.queryDetail(user.getUserId());
System.out.println(detail);
}
@Test
public void queryUserByInnerJoin() {
UserDao userDao = MybatisUtil.getMapper(UserDao.class);
User user = userDao.queryUserByInnerJoin("wangwu");
System.out.println(user);
}
@Test
public void queryUserByAssociation() {
UserDao userDao = MybatisUtil.getMapper(UserDao.class);
User user = userDao.queryUserByAssociation("wangwu");
System.out.println(user);
}
}
一对多关联
一对多的场景为查询一个班级有哪些学生
创建两张表
-- 学生表
CREATE TABLE students (
sid CHAR(5) NOT NULL,
sname VARCHAR(20) NOT NULL,
sage INT NOT NULL,
scid INT NOT NULL
);
-- 班级表
CREATE TABLE classes (
cid INT PRIMARY KEY AUTO_INCREMENT,
cname VARCHAR(30) NOT NULL UNIQUE,
cdesc VARCHAR(100)
);
创建两个实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Student {
private String sId;
private String sName;
private int sAge;
private int sCid;
private Clazz clazz;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Clazz {
private int cId;
private String cName;
private String cDesc;
private List<Student> studentList;
}
创建Dao接口
public interface ClazzDao {
public int insertClazz(Clazz clazz);
public List<Student> queryClazzByInnerJoin(int cId);
public List<Student> queryClazzByAssociation(int cId);
public Clazz queryClazzByCid(int cid);
}
public interface StudentDao {
public int insertStudent(Student student);
public List<Student> queryStudentByCid(int cId);
public List<Student> queryStudentByInnerJoin(String sid);
public List<Student> queryStudentByAssociation(String sid);
}
创建map文件
<?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.kingyal.dao.ClazzDao">
<insert id="insertClazz" useGeneratedKeys="true" keyProperty="cid" timeout="3000" parameterType="Clazz">
insert into classes(cname,cdesc)
values(#{cName},#{cDesc});
</insert>
<!-- 子查询 -->
<resultMap id="ClazzStudentInnerMap" type="Clazz">
<id column="cid" property="cid"></id>
<result column="cname" property="cName"></result>
<result column="cdesc" property="cDesc"></result>
<!-- collection用来申明一个集合;ofType申明元素类型 -->
<collection property="studentList" ofType="Student">
<result column="sid" property="sId"></result>
<result column="sname" property="sName"></result>
<result column="sage" property="sAge"></result>
<result column="scid" property="sCid"></result>
</collection>
</resultMap>
<select id="queryClazzByInnerJoin" resultMap="ClazzStudentInnerMap">
SELECT cid, cname, cdesc, sid, sname, sage,scid
FROM students s INNER JOIN classes c
ON s.scid=c.cid
WHERE c.cid=#{cId};
</select>
<!-- 连接查询 ,如果是集合,用collection,如果是对象,用association -->
<resultMap id="ClazzStudentMap" type="Clazz">
<id column="cid" property="cId"></id>
<result column="cname" property="cName"></result>
<result column="cdesc" property="cDesc"></result>
<collection property="studentList" select="com.kingyal.dao.StudentDao.queryStudentByCid" column="cid"/>
</resultMap>
<select id="queryClazzByAssociation" resultMap="ClazzStudentMap">
SELECT cid, cname, cdesc
FROM classes
WHERE cid=#{cId};
</select>
<resultMap id="ClazzMap" type="Clazz">
<id column="cid" property="cId"></id>
<result column="cname" property="cName"></result>
<result column="cdesc" property="cDesc"></result>
</resultMap>
<select id="queryClazzByCid" resultMap="ClazzMap">
SELECT cid,cname,cdesc
FROM classes c
WHERE c.cid=#{cid};
</select>
</mapper>
<?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.kingyal.dao.StudentDao">
<insert id="insertStudent" useGeneratedKeys="true" keyProperty="sId" timeout="3000" parameterType="Student">
insert into students(sid,sname,sage,scid)
values(#{sId},#{sName},#{sAge},#{sCid});
</insert>
<select id="queryStudentByCid" resultType="Student" resultSets="java.util.List">
select sid,sname,sage,scid
from students
where scid=#{cId};
</select>
<!-- 连接查询 -->
<resultMap id="StudentClazzInnerJoinMap" type="Student">
<id column="sid" property="sId"></id>
<result column="sname" property="sName"></result>
<result column="sage" property="sAge"></result>
<result column="scid" property="sCid"></result>
<result column="cid" property="clazz.cId"></result>
<result column="cname" property="clazz.cName"></result>
<result column="cdesc" property="clazz.cDesc"></result>
</resultMap>
<select id="queryStudentByInnerJoin" resultMap="StudentClazzInnerJoinMap">
SELECT sid, sname,sage,scid,cid,cname,cdesc
FROM students s INNER JOIN classes c
ON s.scid=c.cid
WHERE s.sid=#{sid};
</select>
<!-- 关联查询 -->
<resultMap id="StudentClazzMap" type="Student">
<id column="sid" property="sId"></id>
<result column="sname" property="sName"></result>
<result column="sage" property="sAge"></result>
<result column="scid" property="sCid"></result>
<association property="clazz" select="com.kingyal.dao.ClazzDao.queryClazzByCid" column="scid"></association>
</resultMap>
<select id="queryStudentByAssociation" resultMap="StudentClazzMap">
SELECT sid, sname,sage,scid
FROM students s
WHERE s.sid=#{sid};
</select>
</mapper>
需要将上述两个xml文件加到mybatis的配置文件中:
给实体指定类名:
测试类
可重点关注queryStudentBySid()和queryStudentByAssociation(),他们分别通过连接查询的方式和子查询的方式实现classes表到students表的一对多查询:
public class ClazzDaoTest {
@Test
public void insertClazz() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
try {
Clazz clazz = new Clazz(0,"gaoyi", "it is gaoyi", null);
ClazzDao clazzDao = sqlSession.getMapper(ClazzDao.class);
int i = clazzDao.insertClazz(clazz);
Assert.assertEquals(1, i);
System.out.println(clazz);
Student student1 = new Student("0001", "zhangsan", 13, clazz.getCId(), null, null);
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
i = studentDao.insertStudent(student1);
Assert.assertEquals(1, i);
System.out.println(student1);
Student student2 = new Student("0002", "lisi", 16, clazz.getCId(),null ,null);
i = studentDao.insertStudent(student2);
Assert.assertEquals(1, i);
System.out.println(student2);
Student student3 = new Student("0003", "wangwu", 14, clazz.getCId(),null, null);
i = studentDao.insertStudent(student3);
Assert.assertEquals(1, i);
System.out.println(student3);
sqlSession.commit();
} finally {
sqlSession.rollback();
}
}
@Test
public void queryStudentByCid(){
StudentDao studentDao = MybatisUtil.getMapper(StudentDao.class);
List<Student> studentList = studentDao.queryStudentByCid(2);
System.out.println(studentList);
}
@Test
public void queryClazz() {
ClazzDao clazzDao = MybatisUtil.getMapper(ClazzDao.class);
List<Student> studentList = clazzDao.queryClazzByInnerJoin(2);
System.out.println(studentList);
}
@Test
public void queryClazzByAssociation() {
ClazzDao clazzDao = MybatisUtil.getMapper(ClazzDao.class);
List<Student> studentList = clazzDao.queryClazzByAssociation(2);
System.out.println(studentList);
}
@Test
public void queryStudentBySid() {
StudentDao studentDao = MybatisUtil.getMapper(StudentDao.class);
List<Student> studentList = studentDao.queryStudentByInnerJoin("0001");
System.out.println(studentList);
}
@Test
public void queryClazzByCid() {
ClazzDao clazzDao = MybatisUtil.getMapper(ClazzDao.class);
Clazz clazz = clazzDao.queryClazzByCid(2);
System.out.println(clazz);
}
@Test
public void queryStudentByAssociation() {
StudentDao studentDao = MybatisUtil.getMapper(StudentDao.class);
List<Student> studentList = studentDao.queryStudentByAssociation("0001");
System.out.println(studentList);
}
}
多对多关联
场景为查询哪些学生上哪些课程(学生还是用上述一对多关联时的学生表,学生相关的代码是基于上述已有类做补充),多对多关联时,中间要加一个表进行关联,因此加一个成绩表用来关联。
创建三张表
-- 学生表(已创建)
CREATE TABLE students (
sid CHAR(5) NOT NULL,
sname VARCHAR(20) NOT NULL,
sage INT NOT NULL,
scid INT NOT NULL
);
-- 课程表
CREATE TABLE course(
course_id INT PRIMARY KEY AUTO_INCREMENT,
course_name VARCHAR(50) NOT NULL
);
-- 成绩表
CREATE TABLE grades(
sid CHAR(5) NOT NULL,
cid INT NOT NULL,
score INT NOT NULL
);
创建两个实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Student { // 已经创建
private String sId;
private String sName;
private int sAge;
private int sCid;
private Clazz clazz;
private List<Course> courseList;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Course {
private int courseId;
private String courseName;
private List<Student> studentList;
}
创建两个Dao接口
public interface StudentDao { // 已经创建,基于此类补充了一个接口
public int insertStudent(Student student);
public List<Student> queryStudentByCid(int cId);
public List<Student> queryStudentByInnerJoin(String sid);
public List<Student> queryStudentByAssociation(String sid);
public List<Student> queryStudentByCourseId(int courseId);
}
public interface CourseDao {
public Course queryCourseByInnerJoin(int courseId);
public Course queryCourseByAssociation(int courseId);
}
创建map文件
student还是使用一对多关联的map,基于此map做补充:
<?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.kingyal.dao.StudentDao">
<insert id="insertStudent" useGeneratedKeys="true" keyProperty="sId" timeout="3000" parameterType="Student">
insert into students(sid,sname,sage,scid)
values(#{sId},#{sName},#{sAge},#{sCid});
</insert>
<select id="queryStudentByCid" resultType="Student" resultSets="java.util.List">
select sid,sname,sage,scid
from students
where scid=#{cId};
</select>
<!-- 连接查询 -->
<resultMap id="StudentClazzInnerJoinMap" type="Student">
<id column="sid" property="sId"></id>
<result column="sname" property="sName"></result>
<result column="sage" property="sAge"></result>
<result column="scid" property="sCid"></result>
<result column="cid" property="clazz.cId"></result>
<result column="cname" property="clazz.cName"></result>
<result column="cdesc" property="clazz.cDesc"></result>
</resultMap>
<select id="queryStudentByInnerJoin" resultMap="StudentClazzInnerJoinMap">
SELECT sid, sname,sage,scid,cid,cname,cdesc
FROM students s INNER JOIN classes c
ON s.scid=c.cid
WHERE s.sid=#{sid};
</select>
<!-- 关联查询 -->
<resultMap id="StudentClazzMap" type="Student">
<id column="sid" property="sId"></id>
<result column="sname" property="sName"></result>
<result column="sage" property="sAge"></result>
<result column="scid" property="sCid"></result>
<association property="clazz" select="com.kingyal.dao.ClazzDao.queryClazzByCid" column="scid"></association>
</resultMap>
<select id="queryStudentByAssociation" resultMap="StudentClazzMap">
SELECT sid, sname,sage,scid
FROM students s
WHERE s.sid=#{sid};
</select>
<resultMap id="StudentGradeMap" type="Student">
<id column="sid" property="sId"></id>
<result column="sname" property="sName"></result>
<result column="sage" property="sAge"></result>
<result column="scid" property="sCid"></result>
</resultMap>
<select id="queryStudentByCourseId" resultMap="StudentGradeMap">
SELECT s.sid, s.sname, s.sage, s.scid
FROM students s INNER JOIN grades g
ON g.sid=s.sid
WHERE g.cid=#{courseId};
</select>
</mapper>
<?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.kingyal.dao.CourseDao">
<resultMap id="CourseMap" type="Course">
<id column="course_id" property="courseId"></id>
<result column="course_name" property="courseName"></result>
<collection property="studentList" ofType="Student">
<result column="sid" property="sId"></result>
<result column="sname" property="sName"></result>
<result column="sage" property="sAge"></result>
<result column="scid" property="sCid"></result>
</collection>
</resultMap>
<select id="queryCourseByInnerJoin" resultMap="CourseMap">
SELECT course_id,course_name, s.sid, s.sname, s.sage, s.scid
FROM course c INNER JOIN grades g INNER JOIN students s
ON c.course_id=g.cid AND g.sid=s.sid
WHERE course_id=#{courseId}
</select>
<resultMap id="CourseStudentMap" type="Course">
<id column="course_id" property="courseId"></id>
<result column="course_name" property="courseName"></result>
<collection property="studentList" select="com.kingyal.dao.StudentDao.queryStudentByCourseId" column="course_id">
</collection>
</resultMap>
<select id="queryCourseByAssociation" resultMap="CourseStudentMap">
SELECT course_id,course_name
FROM course
WHERE course_id=#{courseId}
</select>
</mapper>
需要将上述两个xml文件加到mybatis的配置文件中:
给实体指定类名:
测试类
可重点关注queryCourseByInnerJoin()和queryCourseByAssociation(),他们分别通过连接查询的方式和子查询的方式实现students表到course表的多对多查询:
public class CourseDaoTest {
@Test
public void queryCourseByInnerJoin() {
CourseDao courseDao = MybatisUtil.getMapper(CourseDao.class);
Course course = courseDao.queryCourseByInnerJoin(3);
System.out.println(course);
}
@Test
public void queryStudentByCourseId() {
StudentDao studentDao = MybatisUtil.getMapper(StudentDao.class);
List<Student> students = studentDao.queryStudentByCourseId(3);
System.out.println(students);
}
@Test
public void queryCourseByAssociation() {
CourseDao courseDao = MybatisUtil.getMapper(CourseDao.class);
Course course = courseDao.queryCourseByAssociation(3);
System.out.println(course);
}
}