事务管理
获取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 mapperPUBLIC "-//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_imgfrom 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,uidFROM users uINNER JOIN details dON u.user_id=d.uidWHERE u.user_name=#{userName}</select><select id="queryUserByAssociation" resultMap="userDetailMap">SELECT user_id,user_name,user_pwd,user_realname,user_imgFROM users uWHERE u.user_name=#{userName}</select>
</mapper>
如下是detailDao对应的xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//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,uidfrom details where uId=${uId}</select>
</mapper>
需要将上述两个xml文件加到mybatis的配置文件中:
给实体指定类名:
测试类
可重点关注queryUserByInnerJoin()和queryUserByAssociation(),他们分别通过连接查询的方式和子查询的方式实现users表到details表的一对一查询:
public class UserDaoTest {@Testpublic 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();}}@Testpublic 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);}@Testpublic void queryUserByInnerJoin() {UserDao userDao = MybatisUtil.getMapper(UserDao.class);User user = userDao.queryUserByInnerJoin("wangwu");System.out.println(user);}@Testpublic 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 mapperPUBLIC "-//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,scidFROM students s INNER JOIN classes cON s.scid=c.cidWHERE 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, cdescFROM classesWHERE 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,cdescFROM classes cWHERE c.cid=#{cid};</select>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//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,scidfrom studentswhere 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,cdescFROM students s INNER JOIN classes cON s.scid=c.cidWHERE 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,scidFROM students sWHERE s.sid=#{sid};</select>
</mapper>
需要将上述两个xml文件加到mybatis的配置文件中:
给实体指定类名:
测试类
可重点关注queryStudentBySid()和queryStudentByAssociation(),他们分别通过连接查询的方式和子查询的方式实现classes表到students表的一对多查询:
public class ClazzDaoTest {@Testpublic 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();}}@Testpublic void queryStudentByCid(){StudentDao studentDao = MybatisUtil.getMapper(StudentDao.class);List<Student> studentList = studentDao.queryStudentByCid(2);System.out.println(studentList);}@Testpublic void queryClazz() {ClazzDao clazzDao = MybatisUtil.getMapper(ClazzDao.class);List<Student> studentList = clazzDao.queryClazzByInnerJoin(2);System.out.println(studentList);}@Testpublic void queryClazzByAssociation() {ClazzDao clazzDao = MybatisUtil.getMapper(ClazzDao.class);List<Student> studentList = clazzDao.queryClazzByAssociation(2);System.out.println(studentList);}@Testpublic void queryStudentBySid() {StudentDao studentDao = MybatisUtil.getMapper(StudentDao.class);List<Student> studentList = studentDao.queryStudentByInnerJoin("0001");System.out.println(studentList);}@Testpublic void queryClazzByCid() {ClazzDao clazzDao = MybatisUtil.getMapper(ClazzDao.class);Clazz clazz = clazzDao.queryClazzByCid(2);System.out.println(clazz);}@Testpublic 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 mapperPUBLIC "-//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,scidfrom studentswhere 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,cdescFROM students s INNER JOIN classes cON s.scid=c.cidWHERE 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,scidFROM students sWHERE 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.scidFROM students s INNER JOIN grades gON g.sid=s.sidWHERE g.cid=#{courseId};</select>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//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.scidFROM course c INNER JOIN grades g INNER JOIN students sON c.course_id=g.cid AND g.sid=s.sidWHERE 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_nameFROM courseWHERE course_id=#{courseId}</select>
</mapper>
需要将上述两个xml文件加到mybatis的配置文件中:
给实体指定类名:
测试类
可重点关注queryCourseByInnerJoin()和queryCourseByAssociation(),他们分别通过连接查询的方式和子查询的方式实现students表到course表的多对多查询:
public class CourseDaoTest {@Testpublic void queryCourseByInnerJoin() {CourseDao courseDao = MybatisUtil.getMapper(CourseDao.class);Course course = courseDao.queryCourseByInnerJoin(3);System.out.println(course);}@Testpublic void queryStudentByCourseId() {StudentDao studentDao = MybatisUtil.getMapper(StudentDao.class);List<Student> students = studentDao.queryStudentByCourseId(3);System.out.println(students);}@Testpublic void queryCourseByAssociation() {CourseDao courseDao = MybatisUtil.getMapper(CourseDao.class);Course course = courseDao.queryCourseByAssociation(3);System.out.println(course);}
}