MyBatis 是基于 Java 的数据持久层框架
持久化:数据从瞬时状态变为持久状态
持久层:完成持久化工作的代码块 DAO
简而言之:
MyBatis 将数据存入数据库中,从数据库中取数据
通过框架可以减少重复代码,提高开发效率
MyBatis 是一个半自动化的 ORM 框架
Object Relationship Mapping
文档:
https://mybatis.org/mybatis-3/zh/index.html
1、依赖
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4</version>
</dependency>
2、配置数据库
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/data"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="StudentMapper.xml"/>
</mappers>
</configuration>
3、SQL 工厂类
package com.pengshiyu.mybatis.util;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class MyBatisUtil {
public static SqlSessionFactory getSqlSessionFactory() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
return sqlSessionFactory;
}
public static SqlSession getSqlSession() throws IOException {
SqlSession session = getSqlSessionFactory().openSession();
return session;
}
}
4、创建实体类
package com.pengshiyu.mybatis.entity;
public class Student {
private int id;
private String name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
5、编写 SQL 语句映射文件
StudentMapper.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.pengshiyu.mybatis.entity.StudentMapper">
<select id="selectStudent" resultType="com.pengshiyu.mybatis.entity.Student">
select * from students where id = #{id}
</select>
</mapper>
6、测试
package com.pengshiyu.mybatis.test;
import com.pengshiyu.mybatis.entity.Student;
import com.pengshiyu.mybatis.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import java.io.IOException;
public class Demo {
public static void main(String[] args) throws IOException {
SqlSession session = MyBatisUtil.getSqlSession();
Student student = session.selectOne("com.pengshiyu.mybatis.entity.StudentMapper.selectStudent", 3);
System.out.println(student);
session.close();
// Student{id=3, name='李白', age=30}
}
}
curd 操作
StudentMapper.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.pengshiyu.mybatis.entity.StudentMapper">
<select id="selectStudent" resultType="com.pengshiyu.mybatis.entity.Student">
select * from students where id = #{id}
</select>
<select id="selectAllStudent" resultType="com.pengshiyu.mybatis.entity.Student">
select * from students
</select>
<insert id="insertStudent" parameterType="com.pengshiyu.mybatis.entity.Student">
insert into students(name, age) values(#{name}, #{age})
</insert>
<update id="updateStudent" parameterType="com.pengshiyu.mybatis.entity.Student">
update students set name = #{name}, age = #{age} where id = #{id}
</update>
<delete id="deleteStudent">
delete from students where id = #{id}
</delete>
</mapper>
package com.pengshiyu.mybatis.dao;
import com.pengshiyu.mybatis.entity.Student;
import com.pengshiyu.mybatis.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import java.io.IOException;
import java.util.List;
public class StudentDao {
public Student select(int id) throws IOException {
SqlSession session = MyBatisUtil.getSqlSession();
Student student = session.selectOne("com.pengshiyu.mybatis.entity.StudentMapper.selectStudent", id);
session.close();
return student;
}
public List<Student> selectAll() throws IOException {
SqlSession session = MyBatisUtil.getSqlSession();
List<Student> students = session.selectList("com.pengshiyu.mybatis.entity.StudentMapper.selectAllStudent");
session.close();
return students;
}
public int insert(Student student) throws IOException {
SqlSession session = MyBatisUtil.getSqlSession();
int result = session.insert("com.pengshiyu.mybatis.entity.StudentMapper.insertStudent", student);
session.commit();
session.close();
return result;
}
public int update(Student student) throws IOException {
SqlSession session = MyBatisUtil.getSqlSession();
int result = session.update("com.pengshiyu.mybatis.entity.StudentMapper.updateStudent", student);
session.commit();
session.close();
return result;
}
public int delete(int id) throws IOException {
SqlSession session = MyBatisUtil.getSqlSession();
int result = session.delete("com.pengshiyu.mybatis.entity.StudentMapper.deleteStudent", id);
session.commit();
session.close();
return result;
}
}
package com.pengshiyu.mybatis.test;
import com.pengshiyu.mybatis.dao.StudentDao;
import com.pengshiyu.mybatis.entity.Student;
import java.io.IOException;
import java.util.List;
public class Demo {
public static void main(String[] args) throws IOException {
StudentDao studentDao = new StudentDao();
// 查询
Student student = studentDao.select(3);
System.out.println(student);
// Student{id=3, name='李白', age=30}
// 写入
Student student = new Student();
student.setName("Jack");
student.setAge(23);
System.out.println(studentDao.inset(student));
// 1
// 更新
Student student = studentDao.select(16);
student.setAge(33);
student.setName("Tom");
System.out.println(studentDao.update(student));
// 1
// 删除数据
System.out.println(studentDao.delete(12));
// 1
// 查询多条数据
List<Student> students = studentDao.selectAll();
for(Student student: students){
System.out.println(student);
}
}
}
配置文件解析
配置文件
每个数据库对应一个 SqlSessionFactory 实例
dataSource:
- UNPOOLED 每次请求时打开和关闭连接
- POOLED 使用连接池
- JNDI 能在如 EJB 或应用服务器这类容器中使用
mapper 文件
namespace 命名规则:
包名+类名/包名+mapper 文件名
- parameterType 参数类型
- resultType 返回结果类型
- useGeneratedKeys=“true” 使用自增主键
配置优化
执行流程
- 读取核心配置文件
- sqlSessionFactory 类
- sqlSession
- 执行相关操作
1、可以将数据库配置单独放在一个文件里边
db.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/data
username=root
password=123456
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 加载数据库配置 -->
<properties resource="db.properties" />
<settings>
<!-- 打印sql日志 -->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="StudentMapper.xml"/>
</mappers>
</configuration>
2、别名配置
<configuration>
<typeAliases>
<!-- 指定单个类的别名 -->
<typeAlias type="com.pengshiyu.mybatis.entity.Student" alias="Student"/>
<!-- 指定整个包下的类都是别名 -->
<package name="com.pengshiyu.mybatis.entity"/>
</typeAliases>
</configuration>
使用别名
<mapper namespace="com.pengshiyu.mybatis.entity.StudentMapper">
<select id="selectAllStudent" resultType="Student">
select * from students
</select>
</mapper>
属性名和列名不一致
MyBatis 会根据列名取赋值,会将列名转为小写
1、为列名指定别名
<mapper namespace="com.pengshiyu.mybatis.entity.StudentMapper">
<select id="selectStudent" resultType="Student">
select id, name, age as old from students where id = #{id}
</select>
</mapper>
2、使用结果映射类型
<mapper namespace="com.pengshiyu.mybatis.entity.StudentMapper">
<select id="selectStudent" resultMap="StudentMap">
select id, name, age from students where id = #{id}
</select>
<resultMap id="StudentMap" type="Student">
<!-- id为主键 -->
<id column="id" property="id" />
<!-- column是数据库表的列名,property是实体类属性名 -->
<result column="name" property="name"/>
<result column="age" property="age"/>
</resultMap>
</mapper>
分页的实现
1、sql 中实现
如果将数据看做下标从 0 开始,那么就是数据切片 [startIndex, pageSize)
<mapper namespace="com.pengshiyu.mybatis.entity.StudentMapper">
<select id="selectAllStudent" parameterType="Map" resultType="Student">
select * from students limit #{offset}, #{limit}
</select>
</mapper>
public class StudentDao {
public List<Student> selectAll(int currentPage, int pageSize) throws IOException {
SqlSession session = MyBatisUtil.getSqlSession();
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("offset", (currentPage - 1) * pageSize);
map.put("limit", pageSize);
List<Student> students = session.selectList(
"com.pengshiyu.mybatis.entity.StudentMapper.selectAllStudent", map);
session.close();
return students;
}
}
public class Demo {
public static void main(String[] args) throws IOException {
StudentDao studentDao = new StudentDao();
// 查询第二页的数据,每页2条
List<Student> students = studentDao.selectAll(2 , 2);
for(Student student: students){
System.out.println(student);
}
}
}
2、使用 RowBounds
<mapper namespace="com.pengshiyu.mybatis.entity.StudentMapper">
<select id="selectAllStudent" resultType="Student">
select * from students
</select>
</mapper>
import org.apache.ibatis.session.RowBounds;
public class StudentDao {
public List<Student> selectAll(int currentPage, int pageSize) throws IOException {
SqlSession session = MyBatisUtil.getSqlSession();
RowBounds rowBounds = new RowBounds((currentPage - 1) * pageSize, pageSize);
List<Student> students = session.selectList(
"com.pengshiyu.mybatis.entity.StudentMapper.selectAllStudent",
null, rowBounds);
session.close();
return students;
}
}
通过打印的日志发现:
- sql 限制起始位置和返回数量,currentPage=2, pageSize=2 时返回 2 条数据
- RowBounds 不限制起始位置,currentPage=2, pageSize=2 时返回 4 条数据
注解开发
面向接口编程
扩展性好,分层开发中,上层不用管具体实现,
大家都遵循共同的实现,开发变得容易,规范性更好
DAO 接口
package com.pengshiyu.mybatis.dao;
import com.pengshiyu.mybatis.entity.Student;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface IStudentDao {
@Select("select * from students")
public List<Student> getList();
}
修改配置文件
<configuration>
<mappers>
<!-- <mapper resource="StudentMapper.xml"/>-->
<mapper class="com.pengshiyu.mybatis.dao.IStudentDao"/>
</mappers>
</configuration>
测试使用
package com.pengshiyu.mybatis.test;
import com.pengshiyu.mybatis.dao.IStudentDao;
import com.pengshiyu.mybatis.dao.StudentDao;
import com.pengshiyu.mybatis.entity.Student;
import com.pengshiyu.mybatis.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import java.io.IOException;
import java.util.List;
public class Demo {
public static void main(String[] args) throws IOException {
SqlSession session = MyBatisUtil.getSqlSession();
IStudentDao studentDao = session.getMapper(IStudentDao.class);
List<Student> students = studentDao.getList();
for(Student student : students){
System.out.println(student);
}
}
}
多对一的处理
多个学生 student 对一个老师 teacher
1、数据库表设计
create table teachers(
id int PRIMARY key auto_increment,
name varchar(10)
);
create table students(
id int PRIMARY key auto_increment,
name varchar(10),
teacher_id int
);
insert into teachers(name) values("王老师");
insert into teachers(name) values("李老师");
insert into teachers(name) values("赵老师");
insert into students(name, teacher_id) values("宋江", 1);
insert into students(name, teacher_id) values("李逵", 1);
insert into students(name, teacher_id) values("鲁智深", 2);
insert into students(name, teacher_id) values("林冲", 3);
insert into students(name, teacher_id) values("高俅", 3);
2、实体类
Teacher
package com.pengshiyu.mybatis.entity;
public class Teacher {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Teacher{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
Student
package com.pengshiyu.mybatis.entity;
public class Student {
private int id;
private String name;
private Teacher teacher;
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", teacher=" + teacher +
'}';
}
}
3、映射文件
多对一处理方式:
(1)按结果嵌套
查询一次
<mapper namespace="com.pengshiyu.mybatis.entity.StudentMapper">
<select id="selectAllStudent" resultMap="StudentMap">
select s.id sid, s.name sname, t.id tid, t.name tname
from students as s
left join teachers as t
on s.teacher_id = t.id
</select>
<resultMap id="StudentMap" type="Student">
<!-- 主键 -->
<id column="sid" property="id"/>
<result column="sname" property="name"/>
<!-- 关联对象-->
<association property="teacher" javaType="Teacher">
<id column="tid" property="id"/>
<result column="tname" property="name"/>
</association>
</resultMap>
</mapper>
- 按查询嵌套
会查询 n 次,n 是 Student 数量
<mapper namespace="com.pengshiyu.mybatis.entity.StudentMapper">
<select id="selectAllStudent" resultMap="StudentTeacher">
select * from students
</select>
<resultMap id="StudentTeacher" type="Student">
<!-- 关联对象-->
<association property="teacher" column="teacher_id"
javaType="Teacher" select="getTeacher">
<id column="tid" property="id"/>
<result column="tname" property="name"/>
</association>
</resultMap>
<select id="getTeacher" resultType="Teacher">
select * from teachers where id = #{id}
</select>
</mapper>
4、引入映射文件
mybatis-config.xml
<configuration>
<typeAliases>
<package name="com.pengshiyu.mybatis.entity"/>
</typeAliases>
<mappers>
<mapper resource="StudentMapper.xml"/>
</mappers>
</configuration>
5、Dao 编写
package com.pengshiyu.mybatis.dao;
import com.pengshiyu.mybatis.entity.Student;
import com.pengshiyu.mybatis.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import java.io.IOException;
import java.util.List;
public class StudentDao {
public List<Student> selectAll() throws IOException {
SqlSession session = MyBatisUtil.getSqlSession();
List<Student> students = session.selectList(
"com.pengshiyu.mybatis.entity.StudentMapper.selectAllStudent");
session.close();
return students;
}
}
6、测试类
package com.pengshiyu.mybatis.test;
import com.pengshiyu.mybatis.dao.StudentDao;
import com.pengshiyu.mybatis.entity.Student;
import java.io.IOException;
import java.util.List;
public class Demo {
public static void main(String[] args) throws IOException {
StudentDao studentDao = new StudentDao();
List<Student> students = studentDao.selectAll();
for(Student student: students){
System.out.println(student);
}
}
}
查询结果
Student{id=1, name='宋江', teacher=Teacher{id=1, name='王老师'}}
Student{id=2, name='李逵', teacher=Teacher{id=1, name='王老师'}}
Student{id=3, name='鲁智深', teacher=Teacher{id=2, name='李老师'}}
Student{id=4, name='林冲', teacher=Teacher{id=3, name='赵老师'}}
Student{id=5, name='高俅', teacher=Teacher{id=3, name='赵老师'}}
一对多关系
Teacher
package com.pengshiyu.mybatis.entity;
import java.util.List;
public class Teacher {
private int id;
private String name;
private List<Student> students;
public List<Student> getStudents() {
return students;
}
public void setStudents(List<Student> students) {
this.students = students;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Teacher{" +
"id=" + id +
", name='" + name + '\'' +
", students=" + students +
'}';
}
}
TeacherMapper
查询一次
<mapper namespace="com.pengshiyu.mybatis.entity.TeacherMapper">
<select id="selectOneTeacher" resultMap="TeacherStudent">
select t.id tid, t.name tname, s.id sid, s.name sname
from teachers t left join students s
on t.id = s.teacher_id
where t.id = #{id}
</select>
<resultMap id="TeacherStudent" type="Teacher">
<id column="tid" property="id"/>
<result column="tname" property="name"/>
<!-- 关联集合 -->
<collection property="students" ofType="Student">
<id column="sid" property="id"/>
<result column="sname" property="name"/>
</collection>
</resultMap>
</mapper>
查询两次
<mapper namespace="com.pengshiyu.mybatis.entity.TeacherMapper">
<select id="selectOneTeacher" resultMap="TeacherStudent">
select *
from teachers
where id = #{id}
</select>
<resultMap id="TeacherStudent" type="Teacher">
<!-- 关联集合 -->
<!-- column 是外键 -->
<collection property="students" column="id" ofType="Student"
select="getStudentByTeacherId">
</collection>
</resultMap>
<select id="getStudentByTeacherId" resultType="Student">
select * from students where teacher_id = #{id}
</select>
</mapper>
mybatis-config.xml
<configuration>
<typeAliases>
<package name="com.pengshiyu.mybatis.entity"/>
</typeAliases>
<mappers>
<mapper resource="TeacherMapper.xml"/>
</mappers>
</configuration>
TeacherDao
package com.pengshiyu.mybatis.dao;
import com.pengshiyu.mybatis.entity.Student;
import com.pengshiyu.mybatis.entity.Teacher;
import com.pengshiyu.mybatis.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import java.io.IOException;
import java.util.List;
public class TeacherDao {
public Teacher selectOne(int id) throws IOException {
SqlSession session = MyBatisUtil.getSqlSession();
Teacher teacher = session.selectOne(
"com.pengshiyu.mybatis.entity.TeacherMapper.selectOneTeacher", id);
session.close();
return teacher;
}
}
package com.pengshiyu.mybatis.test;
import com.pengshiyu.mybatis.dao.StudentDao;
import com.pengshiyu.mybatis.dao.TeacherDao;
import com.pengshiyu.mybatis.entity.Student;
import com.pengshiyu.mybatis.entity.Teacher;
import java.io.IOException;
import java.util.List;
public class Demo {
public static void main(String[] args) throws IOException {
TeacherDao teacherDao = new TeacherDao();
Teacher teacher = teacherDao.selectOne(1);
System.out.println(teacher);
for(Student student: teacher.getStudents()){
System.out.println(student);
}
}
}
输出
Teacher{id=1, name='王老师', students=[
Student{id=1, name='宋江', teacher=null},
Student{id=2, name='李逵', teacher=null}
]
}
Student{id=1, name='宋江', teacher=null}
Student{id=2, name='李逵', teacher=null}
动态 SQL
根据不同的查询条件,生成不同的 sql
<mapper namespace="com.pengshiyu.mybatis.entity.StudentMapper">
<select id="selectAllStudent" resultType="Student">
select * from students
<where>
<if test="name != null">
name = #{name}
</if>
</where>
</select>
</mapper>
sql:
select * from students WHERE name = ?
package com.pengshiyu.mybatis.dao;
import com.pengshiyu.mybatis.entity.Student;
import com.pengshiyu.mybatis.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class StudentDao {
public List<Student> selectAllStudent(String name) throws IOException {
SqlSession session = MyBatisUtil.getSqlSession();
Map<String, String> map = new HashMap<>();
map.put("name", name);
List<Student> students = session.selectList(
"com.pengshiyu.mybatis.entity.StudentMapper.selectAllStudent",
map
);
session.close();
return students;
}
}
package com.pengshiyu.mybatis.test;
import com.pengshiyu.mybatis.dao.StudentDao;
import com.pengshiyu.mybatis.entity.Student;
import java.io.IOException;
import java.util.List;
public class Demo {
public static void main(String[] args) throws IOException {
StudentDao studentDao = new StudentDao();
List<Student> students = studentDao.selectAllStudent("宋江");
for(Student student: students){
System.out.println(student);
}
}
}