一.Mybatis入门
1.1 框架介绍
- 框架是一款半成品软件,我们可以基于这个半成品软件继续开发,来完成我们个性化的需求!
1.2 ORM介绍
-
ORM(Object Relational Mapping): 对象关系映射
- object:指的是实体对象,javabean
- relational:指的是关系型数据库,比如mysql
-
指的是持久化数据和实体对象的映射模式,为了解决面向对象与关系型数据库存在的互不匹配的现象的技术。
-
简单说,ORM 就是通过实例对象的语法,完成关系型数据库的操作的技术,是"对象-关系映射"(Object/Relational Mapping)的缩写
-
ORM 把数据库映射成对象,具体映射关系如下:
数据库的表(table) --> 类(class) 记录(record,行数据) --> 对象(Object) 字段(field) --> 对象的属性(attribute)
1.3 什么是Mybatis
-
mybatis 是一个优秀的基于java的持久层框架,它内部封装了jdbc,使开发者只需要关注sql语句本身,而不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程
-
mybatis通过xml或注解的方式将要执行的各种 statement配置起来,并通过java对象和statement中sql的动态参数进行映射生成最终执行的sql语句
-
最后mybatis框架执行sql并将结果映射为java对象并返回。采用ORM思想解决了实体和数据库映射的问题,对jdbc 进行了封装,屏蔽了jdbc api 底层访问细节,使我们不用与jdbc api 打交道,就可以完成对数据库的持久化操作
1.4 Mybatis的快速入门
MyBatis开发步骤:
①添加MyBatis的jar包
②创建Student数据表
③编写Student实体类
④编写映射文件StudentMapper.xml
⑤编写核心文件MyBatisConfig.xml
⑥编写测试类
1.4.1 环境搭建
-
新建java项目:
-
导入MyBatis的jar包
- mysql-connector-java-5.1.37-bin.jar
- mybatis-3.5.3.jar
- junit-4.9.jar
- 创建student数据表
CREATE TABLE student(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
age INT
);
INSERT INTO student VALUES
(NULL,'张三',23),
(NULL,'李四',24),
(NULL,'王五',25);
- 编写Student实体
public class Student {
private Integer id;
private String name;
private Integer age;
//Getter and Setter
}
- 新建测试类
public class StudentTest01 {
/*
查询全部
*/
@Test
public void selectAll() throws Exception{
//1.加载核心配置文件
//2.获取SqlSession工厂对象
//3.通过SqlSession工厂对象获取SqlSession对象
//4.执行映射配置文件中的sql语句,并接收结果
//5.处理结果
//6.释放资源
}
}
- 编写src/StudentMapper.xml映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!--MyBatis的DTD约束 直接复制-->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
mapper:核心根标签
namespace属性:名称空间
-->
<mapper namespace="StudentMapper">
<!--
select:查询功能的标签
id属性:唯一标识
resultType属性:指定结果映射对象类型
parameterType属性:指定参数映射对象类型
-->
<select id="selectAll" resultType="com.lichee.bean.Student">
SELECT * FROM student
</select>
</mapper>
- 编写MyBatis核心文件: src/MyBatisConfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!--MyBatis的DTD约束 直接复制-->
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration 核心根标签-->
<configuration>
<!--environments配置数据库环境,环境可以有多个。default属性指定使用的是哪个-->
<environments default="mysql">
<!--environment配置数据库环境 id属性唯一标识-->
<environment id="mysql">
<!-- transactionManager事务管理。 type属性,采用JDBC默认的事务-->
<transactionManager type="JDBC"></transactionManager>
<!-- dataSource数据源信息 type属性 连接池-->
<dataSource type="POOLED">
<!-- property获取数据库连接的配置信息 -->
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/db1" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
<!-- mappers引入映射配置文件 -->
<mappers>
<!-- mapper 引入指定的映射配置文件 resource属性指定映射配置文件的名称 -->
<mapper resource="StudentMapper.xml"/>
</mappers>
</configuration>
1.4.2 编写测试代码
@Test
public void selectAll() throws Exception{
//1.加载核心配置文件
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
//2.获取SqlSession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//3.通过SqlSession工厂对象获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//4.执行映射配置文件中的sql语句,并接收结果(参数是StudentMapper.xml中的selectAll)
List<Student> list = sqlSession.selectList("StudentMapper.selectAll");
//5.处理结果
for (Student stu : list) {
System.out.println(stu);
}
//6.释放资源
sqlSession.close();
is.close();
}
1.5 知识小结
-
框架
框架是一款半成品软件,我们可以基于框架继续开发,从而完成一些个性化的需求。
-
ORM
对象关系映射,数据和实体对象的映射。
-
MyBatis
是一个优秀的基于 Java 的持久层框架,它内部封装了 JDBC。
二. MyBatis的相关API
2.1 Resources
-
org.apache.ibatis.io.Resources:加载资源的工具类
- mybatis的前身就是ibatis
-
核心方法
返回值 方法名 说明 InputStream getResourceAsStream(String fileName) 通过类加载器返回指定资源的字节输入流 -
如果不使用Resources,那我们可以自己使用类加载器(但是麻烦)
//InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); InputStream is = StudentTest01.class.getClassLoader().getResourceAsStream("MyBatisConfig.xml");
2.2 构建器SqlSessionFactoryBuilder
-
org.apache.ibatis.session.SqlSessionFactoryBuilder:获取 SqlSessionFactory 工厂对象的功能类
-
核心方法
返回值 方法名 说明 SqlSessionFactory build(InputStream is) 通过指定资源字节输入流获取SqlSession工厂对象 -
通过加载mybatis的核心文件的输入流的形式构建一个SqlSessionFactory对象
InputStream inputStream = Resources.getResourceAsStream("MyBatisConfig.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory fact ory = builder.build(inputStream);
2.3 工厂对象SqlSessionFactory
-
org.apache.ibatis.session.SqlSessionFactory:获取 SqlSession 构建者对象的工厂接口。
-
核心api
返回值 方法名 说明 SqlSession openSession() 获取SqlSession构建者对象,并开启手动提交事务 SqlSession openSession(boolean autoCommit) 获取SqlSession构建者对象,如果参数为true,则开启自动提交事务
-
代码
//3.通过SqlSession工厂对象获取SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); //4.执行映射配置文件中的sql语句,并接收结果 List<Student> list = sqlSession.selectList("StudentMapper.selectAll");
- 说明:因为我们的代码是执行了一个查询的语句,所以不用处理事务
2.4 SqlSession会话对象
-
org.apache.ibatis.session.SqlSession:构建者对象接口。用于执行 SQL、管理事务、接口代理。
-
核心api
返回值 方法名 说明 List selectList(String statement,Object paramter) 执行查询语句,返回List集合 T selectOne(String statement,Object paramter) 执行查询语句,返回一个结果对象 int insert(String statement,Object paramter) 执行新增语句,返回影响行数 int update(String statement,Object paramter) 执行修改语句,返回影响行数 int delete(String statement,Object paramter) 执行删除语句,返回影响行数 void commit() 提交事务 void rollback() 回滚事务 T getMapper(class cls) 获取指定接口的代理实现类对象 void close() 释放资源
-
SqlSession 实例在 MyBatis 中是非常强大的一个类。在这里你会看到所有执行语句、提交或回滚事务和获取映射器实例的方法
-
作用:
- 通过SqlSession对象,主要用途执行sql语句,对数据库进行操作
-
本质:
- SqlSession 可以理解为相当于一个数据库连接(Connection 对象),你可以在一个事务里面执行多条 SQL,然后通过它的 commit、rollback 等方法,提交或者回滚事务
- 所以它应该存活在一个业务请求中,处理完整个请求后,应该关闭这条连接,让它归还给SqlSessionFactory,否则数据库资源就很快被耗费精光,系统就会瘫痪,所以用 try…catch…finally… 语句来保证其正确关闭
2.5 小结
- Resources
- 加载资源的工具类
- SqlSessionFactoryBuilder
- 获取 SqlSessionFactory 工厂对象的功能类
- SqlSessionFactory
- 获取 SqlSession 构建者对象的工厂接口
- 指定事务的提交方式
- SqlSession
- 构建者对象接口
- 执行 SQL
- 管理事务
- 接口代理
三.MyBatis 映射配置文件
3.1 映射配置文件介绍
-
映射配置文件包含了数据和对象之间的映射关系以及要执行的 SQL 语句
<?xml version="1.0" encoding="UTF-8" ?> <!--MyBatis的DTD约束--> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- mapper:核心根标签 namespace属性:名称空间 --> <mapper namespace="StudentMapper"> <!-- select:查询功能的标签 id属性:唯一标识 resultType属性:指定结果映射对象类型 parameterType属性:指定参数映射对象类型 --> <select id="selectAll" resultType="com.lichee.bean.Student"> SELECT * FROM student </select> </mapper>
- 这个namespace,命名空间,相当于是给这个映射节点,起一个名字
- 内部的所有增删改查的配置,都需要通过这个命名空间获取
- 语法:命名空间.id
3.2 查询功能
-
<select>
:查询功能标签 -
属性
id:唯一标识, 配合名称空间使用。
parameterType:指定参数映射的对象类型
resultType:指定结果映射的对象类型
-
SQL 获取参数:#{属性名}
-
修改StudentMapper.xml,增加如下:
<select id="selectById" resultType="com.lichee.bean.Student" parameterType="java.lang.Integer"> SELECT * FROM student WHERE id = #{id} </select>
- 因为参数类型是Integer,所以可以改名字
- 但是这里的参数名一般是与数据库列名和Student的列名一致的
-
测试类StudentTest01.java,新增代码:
/* 根据id查询 */ @Test public void selectById() throws Exception{ //1.加载核心配置文件 InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); //2.获取SqlSession工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); //3.通过工厂对象获取SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); //4.执行映射配置文件中的sql语句,并接收结果 Student stu = sqlSession.selectOne("StudentMapper.selectById", 3); //5.处理结果 System.out.println(stu); //6.释放资源 sqlSession.close(); is.close(); }
3.3 新增功能
-
<insert>
:新增功能标签 -
属性
id:唯一标识, 配合名称空间使用
parameterType:指定参数映射的对象类型
resultType:指定结果映射的对象类型
-
SQL 获取参数:#{属性名}
-
修改StudentMapper.xml,增加如下:
<insert id="insert" parameterType="com.lichee.bean.Student"> INSERT INTO student VALUES (#{id},#{name},#{age}) </insert>
- 注意:因为这里的参数类型是Student,所以参数名必须与Student的字段保持一致
-
测试类StudentTest01.java,新增代码:
/* 新增功能 */ @Test public void insert() throws Exception{ //1.加载核心配置文件 InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); //2.获取SqlSession工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); //3.通过工厂对象获取SqlSession对象 //SqlSession sqlSession = sqlSessionFactory.openSession(); // 自动提交事务 SqlSession sqlSession = sqlSessionFactory.openSession(true); //4.执行映射配置文件中的sql语句,并接收结果 Student stu = new Student(5,"周七",27); int result = sqlSession.insert("StudentMapper.insert", stu); //5.提交事务(手动提交事务) //sqlSession.commit(); //6.处理结果 System.out.println(result); //7.释放资源 sqlSession.close(); is.close(); }
3.4 修改功能
-
<update>
:修改功能标签 -
属性
id:唯一标识, 配合名称空间使用
parameterType:指定参数映射的对象类型
resultType:指定结果映射的对象类型
-
SQL 获取参数: #{属性名}
-
修改StudentMapper.xml,增加如下:
<update id="update" parameterType="com.lichee.bean.Student"> UPDATE student SET name = #{name},age = #{age} WHERE id = #{id} </update>
- 注意:因为这里的参数类型是Student,所以参数名必须与Student的字段保持一致
-
测试类StudentTest01.java,新增代码:
/* 修改功能 */ @Test public void update() throws Exception{ //1.加载核心配置文件 InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); //2.获取SqlSession工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); //3.通过工厂对象获取SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); //4.执行映射配置文件中的sql语句,并接收结果 Student stu = new Student(5,"周七",37); int result = sqlSession.update("StudentMapper.update",stu); //5.提交事务 sqlSession.commit(); //6.处理结果 System.out.println(result); //7.释放资源 sqlSession.close(); is.close(); }
3.5 删除功能
-
<delete>
:查询功能标签。 -
属性
id:唯一标识, 配合名称空间使用。
parameterType:指定参数映射的对象类型。
resultType:指定结果映射的对象类型。
-
SQL 获取参数:#{属性名}
-
修改StudentMapper.xml,增加如下:
<delete id="delete" parameterType="java.lang.Integer"> DELETE FROM student WHERE id = #{id} </delete>
-
测试类StudentTest01.java,新增代码:
/* 删除功能 */ @Test public void delete() throws Exception{ //1.加载核心配置文件 InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); //2.获取SqlSession工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); //3.通过工厂对象获取SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); //4.执行映射配置文件中的sql语句,并接收结果 int result = sqlSession.delete("StudentMapper.delete",5); //5.提交事务 sqlSession.commit(); //6.处理结果 System.out.println(result); //7.释放资源 sqlSession.close(); is.close(); }
-
总结: 可以发现crud操作,除了标签名称以及sql语句不一样之外,其他属性参数基本一致。
3.6 映射配置文件小结
- 映射配置文件包含了数据和对象之间的映射关系以及要执行的SQL语句。
<mapper>
:核心根标签。- namespace 属性:名称空间
<select>
:查询功能标签。<insert>
:新增功能标签。<update>
:修改功能标签。<delete>
:删除功能标签。- id 属性:唯一标识,配合名称空间使用
- parameterType 属性:指定参数映射的对象类型
- resultType 属性:指定结果映射的对象类型
- SQL获取参数
- #{属性名}
四.Mybatis核心配置文件介绍
4.1 核心配置文件介绍
核心配置文件包含了 MyBatis 最核心的设置和属性信息。如数据库的连接、事务、连接池信息等。如下图:
<?xml version="1.0" encoding="UTF-8" ?>
<!--MyBatis的DTD约束-->
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration 核心根标签-->
<configuration>
<!--environments配置数据库环境,环境可以有多个。default属性指定使用的是哪个-->
<environments default="mysql">
<!--environment配置数据库环境 id属性唯一标识-->
<environment id="mysql">
<!-- transactionManager事务管理。 type属性,采用JDBC默认的事务-->
<transactionManager type="JDBC"></transactionManager>
<!-- dataSource数据源信息 type属性 连接池-->
<dataSource type="POOLED">
<!-- property获取数据库连接的配置信息 -->
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/db1" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
<!-- mappers引入映射配置文件 -->
<mappers>
<!-- mapper 引入指定的映射配置文件 resource属性指定映射配置文件的名称 -->
<mapper resource="StudentMapper.xml"/>
</mappers>
</configuration>
4.2 数据库连接配置文件引入
- properties标签作用:
- 引入外部的数据库配置文件
- 标签属性
- resource:数据库连接配置文件路径
- 获取数据库连接参数的语法格式
- ${键名}
- 优点
- 便于灵活的修改数据库连接池配置参数.
-
创建:src/jdbc.properties
driver=com.mysql.jdbc.Driver url=jdbc:mysql://127.0.0.1:3306/db1 username=root password=root
-
修改MyBatisConfig.xml配置文件:properties标签引入外部文件
<!--引入数据库连接的配置文件--> <properties resource="jdbc.properties"/> <!-- property获取数据库连接的配置信息 --> <property name="driver" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" />
4.3 起别名
-
<typeAliases>
:为全类名起别名的父标签。 -
<typeAlias>
:为全类名起别名的子标签。 -
属性
type:指定全类名
alias:指定别名
-
<package>
:为指定包下所有类起别名的子标签。(别名就是类名) -
如下图:
别名 数据类型 string java.lang.String long java.lang.Long int java.lang.Integer double java.lang.Double boolean java.lang.Boolean … … -
具体如下配置:修改MyBatisConfig.xml,增加代码如下:
<!--起别名--> <typeAliases> <typeAlias type="com.lichee.bean.Student" alias="student"/> <!--<package name="com.lichee.bean"/> 如果bean包下有很多Javabean都需要起别名,就可以使用package,指定一个包名 这样的话,就自动给这个包下所有的类添加别名,别名是类名的小写名字 --> </typeAliase> </typeAliases>
-
然后使用的时候就方便了,修改StudentMapper.xml中的com.lichee.bean.Student
<select id="selectAll" resultType="student"> SELECT * FROM student </select> <select id="selectById" resultType="student" parameterType="int"> SELECT * FROM student WHERE id = #{id} </select> <insert id="insert" parameterType="student"> INSERT INTO student VALUES (#{id},#{name},#{age}) </insert> <update id="update" parameterType="student"> UPDATE student SET name = #{name},age = #{age} WHERE id = #{id} </update> <delete id="delete" parameterType="int"> DELETE FROM student WHERE id = #{id} </delete>
4.4 总结
- 核心配置文件包含了 MyBatis 最核心的设置和属性信息。如数据可得连接、事务、连接池信息等。
<configuration>
:核心根标签。<properties>
:引入数据库连接信息配置文件标签。<typeAliases>
:起别名标签。<environments>
:配置数据库环境标签。<environment>
:配置数据库信息标签。<transactionManager>
:事务管理标签。<dataSource>
:数据源标签。<property>
:数据库连接信息标签。<mappers>
:引入映射配置文件标签。
五.Mybatis传统方式开发
5.1 Dao 层传统实现方式
- 分层思想:控制层(controller)、业务层(service)、持久层(dao)。
- 调用流程
- 控制层→业务层→持久层→DB
5.1.1 准备工作
-
实现步骤
- 在controller包下: 新建StudentContoller类
- 在service包下: 新建StudentService接口以及StudentServiceImpl实现类
- 在mapper包下:新建StudentMapper接口以及StudentMapperImpl实现类
- StudentContoller----->StudentService----->StudentMapper
-
在mybatis项目中持久层就不再叫dao了,而是叫做mapper(其实都是一样的,就是换个名字)
-
StudentMapper接口
/* 持久层接口 */ public interface StudentMapper { //查询全部 public abstract List<Student> selectAll(); //根据id查询 public abstract Student selectById(Integer id); //新增数据 public abstract Integer insert(Student stu); //修改数据 public abstract Integer update(Student stu); //删除数据 public abstract Integer delete(Integer id); }
-
StudentMapperImpl实现类
/* 持久层实现类 */ public class StudentMapperImpl implements StudentMapper { /* 查询全部 */ @Override public List<Student> selectAll() { } /* 根据id查询 */ @Override public Student selectById(Integer id) { } /* 新增功能 */ @Override public Integer insert(Student stu) { } /* 修改功能 */ @Override public Integer update(Student stu) { } /* 删除功能 */ @Override public Integer delete(Integer id) { } }
-
StudentService接口
/* 业务层接口 */ public interface StudentService { //查询全部 public abstract List<Student> selectAll(); //根据id查询 public abstract Student selectById(Integer id); //新增数据 public abstract Integer insert(Student stu); //修改数据 public abstract Integer update(Student stu); //删除数据 public abstract Integer delete(Integer id); }
-
StudentServiceImpl实现类
/* 业务层实现类 */ public class StudentServiceImpl implements StudentService { //创建持久层对象 private StudentMapper mapper = new StudentMapperImpl(); @Override public List<Student> selectAll() { return mapper.selectAll(); } @Override public Student selectById(Integer id) { return mapper.selectById(id); } @Override public Integer insert(Student stu) { return mapper.insert(stu); } @Override public Integer update(Student stu) { return mapper.update(stu); } @Override public Integer delete(Integer id) { return mapper.delete(id); } }
-
StudentController测试类:
/* 控制层测试类 */ public class StudentController { //创建业务层对象 private StudentService service = new StudentServiceImpl(); //查询全部功能测试 @Test public void selectAll() { List<Student> students = service.selectAll(); for (Student stu : students) { System.out.println(stu); } } //根据id查询功能测试 @Test public void selectById() { Student stu = service.selectById(3); System.out.println(stu); } //新增功能测试 @Test public void insert() { Student stu = new Student(4,"赵六",26); Integer result = service.insert(stu); System.out.println(result); } //修改功能测试 @Test public void update() { Student stu = new Student(4,"赵六",16); Integer result = service.update(stu); System.out.println(result); } //删除功能测试 @Test public void delete() { Integer result = service.delete(4); System.out.println(result); } }
5.1.2 持久层功能实现
/*
持久层实现类
*/
public class StudentMapperImpl implements StudentMapper {
/*
查询全部
*/
@Override
public List<Student> selectAll() {
List<Student> list = null;
SqlSession sqlSession = null;
InputStream is = null;
try{
//1.加载核心配置文件
is = Resources.getResourceAsStream("MyBatisConfig.xml");
//2.获取SqlSession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//3.通过工厂对象获取SqlSession对象
sqlSession = sqlSessionFactory.openSession(true);
//4.执行映射配置文件中的sql语句,并接收结果
list = sqlSession.selectList("StudentMapper.selectAll");
} catch (Exception e) {
e.printStackTrace();
} finally {
//5.释放资源
if(sqlSession != null) {
sqlSession.close();
}
if(is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//6.返回结果
return list;
}
/*
根据id查询
*/
@Override
public Student selectById(Integer id) {
Student stu = null;
SqlSession sqlSession = null;
InputStream is = null;
try{
//1.加载核心配置文件
is = Resources.getResourceAsStream("MyBatisConfig.xml");
//2.获取SqlSession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//3.通过工厂对象获取SqlSession对象
sqlSession = sqlSessionFactory.openSession(true);
//4.执行映射配置文件中的sql语句,并接收结果
stu = sqlSession.selectOne("StudentMapper.selectById",id);
} catch (Exception e) {
e.printStackTrace();
} finally {
//5.释放资源
if(sqlSession != null) {
sqlSession.close();
}
if(is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//6.返回结果
return stu;
}
/*
新增功能
*/
@Override
public Integer insert(Student stu) {
Integer result = null;
SqlSession sqlSession = null;
InputStream is = null;
try{
//1.加载核心配置文件
is = Resources.getResourceAsStream("MyBatisConfig.xml");
//2.获取SqlSession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//3.通过工厂对象获取SqlSession对象
sqlSession = sqlSessionFactory.openSession(true);
//4.执行映射配置文件中的sql语句,并接收结果
result = sqlSession.insert("StudentMapper.insert",stu);
} catch (Exception e) {
e.printStackTrace();
} finally {
//5.释放资源
if(sqlSession != null) {
sqlSession.close();
}
if(is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//6.返回结果
return result;
}
/*
修改功能
*/
@Override
public Integer update(Student stu) {
Integer result = null;
SqlSession sqlSession = null;
InputStream is = null;
try{
//1.加载核心配置文件
is = Resources.getResourceAsStream("MyBatisConfig.xml");
//2.获取SqlSession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//3.通过工厂对象获取SqlSession对象
sqlSession = sqlSessionFactory.openSession(true);
//4.执行映射配置文件中的sql语句,并接收结果
result = sqlSession.update("StudentMapper.update",stu);
} catch (Exception e) {
e.printStackTrace();
} finally {
//5.释放资源
if(sqlSession != null) {
sqlSession.close();
}
if(is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//6.返回结果
return result;
}
/*
删除功能
*/
@Override
public Integer delete(Integer id) {
Integer result = null;
SqlSession sqlSession = null;
InputStream is = null;
try{
//1.加载核心配置文件
is = Resources.getResourceAsStream("MyBatisConfig.xml");
//2.获取SqlSession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//3.通过工厂对象获取SqlSession对象
sqlSession = sqlSessionFactory.openSession(true);
//4.执行映射配置文件中的sql语句,并接收结果
result = sqlSession.delete("StudentMapper.delete",id);
} catch (Exception e) {
e.printStackTrace();
} finally {
//5.释放资源
if(sqlSession != null) {
sqlSession.close();
}
if(is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//6.返回结果
return result;
}
}
5.2 LOG4J的配置和使用
-
在日常开发过程中,排查问题时难免需要输出 MyBatis 真正执行的 SQL 语句、参数、结果等信息,我们就可以借助 LOG4J 的功能来实现执行信息的输出。
-
使用步骤:
-
导入 jar 包:
- log4j-1.2.17.jar
-
修改核心配置文件:MyBatisConfig.xml
<!--配置LOG4J:以下name和value是固定写法--> <settings> <setting name="logImpl" value="log4j"/> </settings>
-
在 src 下编写 LOG4J 配置文件 : log4j.properties (配置文件名字也是固定写法)
# Global logging configuration # 日志的四个级别,从高到低:ERROR(错误信息) WARN(警告信息) INFO(普通信息) DEBUG(调试信息,推荐使用) # stdout:输出到控制台 log4j.rootLogger=DEBUG, stdout # 输出格式 log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
-
六.接口代理方式实现Dao
6.1 代理开发方式介绍
-
采用 Mybatis 的代理开发方式实现 DAO 层的开发,这种方式是企业的主流。
-
Mapper 接口开发方法只需要程序员编写Mapper 接口(相当于Dao 接口),由Mybatis 框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法
-
总结:接口代理方式,其实就我们自己不用实现MapperImpl(持久层实现类),mybatis通过接口代理的方式帮助我们实现
-
Mapper 接口开发需要遵循以下规范:
1) Mapper.xml文件中的namespace与mapper接口的全限定名相同
2) Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
3) Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同
4) Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
6.2 代码实现
- 实现步骤:
-
删除 mapper 层接口的实现类
-
修改映射配置文件
<!-- 将命名空间修改为StudentMapper全路径名--> <mapper namespace="com.lichee.mapper.StudentMapper">
-
修改 service 层接口的实现类,采用接口代理方式实现功能(因为现在没有持久层实现类了,所以业务层无法直接调用,需要自己实现并且调用代理接口方式的MapperImpl)
/* 业务层实现类 */ public class StudentServiceImpl implements StudentService { @Override public List<Student> selectAll() { List<Student> list = null; SqlSession sqlSession = null; InputStream is = null; try{ //1.加载核心配置文件 is = Resources.getResourceAsStream("MyBatisConfig.xml"); //2.获取SqlSession工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); //3.通过工厂对象获取SqlSession对象 sqlSession = sqlSessionFactory.openSession(true); //4.获取StudentMapper接口的实现类对象 StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // StudentMapper mapper = new StudentMapperImpl(); //5.通过实现类对象调用方法,接收结果 list = mapper.selectAll(); } catch (Exception e) { } finally { //6.释放资源 if(sqlSession != null) { sqlSession.close(); } if(is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } //7.返回结果 return list; } @Override public Student selectById(Integer id) { Student stu = null; SqlSession sqlSession = null; InputStream is = null; try{ //1.加载核心配置文件 is = Resources.getResourceAsStream("MyBatisConfig.xml"); //2.获取SqlSession工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); //3.通过工厂对象获取SqlSession对象 sqlSession = sqlSessionFactory.openSession(true); //4.获取StudentMapper接口的实现类对象 StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // StudentMapper mapper = new StudentMapperImpl(); //5.通过实现类对象调用方法,接收结果 stu = mapper.selectById(id); } catch (Exception e) { } finally { //6.释放资源 if(sqlSession != null) { sqlSession.close(); } if(is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } //7.返回结果 return stu; } @Override public Integer insert(Student stu) { Integer result = null; SqlSession sqlSession = null; InputStream is = null; try{ //1.加载核心配置文件 is = Resources.getResourceAsStream("MyBatisConfig.xml"); //2.获取SqlSession工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); //3.通过工厂对象获取SqlSession对象 sqlSession = sqlSessionFactory.openSession(true); //4.获取StudentMapper接口的实现类对象 StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // StudentMapper mapper = new StudentMapperImpl(); //5.通过实现类对象调用方法,接收结果 result = mapper.insert(stu); } catch (Exception e) { } finally { //6.释放资源 if(sqlSession != null) { sqlSession.close(); } if(is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } //7.返回结果 return result; } @Override public Integer update(Student stu) { Integer result = null; SqlSession sqlSession = null; InputStream is = null; try{ //1.加载核心配置文件 is = Resources.getResourceAsStream("MyBatisConfig.xml"); //2.获取SqlSession工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); //3.通过工厂对象获取SqlSession对象 sqlSession = sqlSessionFactory.openSession(true); //4.获取StudentMapper接口的实现类对象 StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // StudentMapper mapper = new StudentMapperImpl(); //5.通过实现类对象调用方法,接收结果 result = mapper.update(stu); } catch (Exception e) { } finally { //6.释放资源 if(sqlSession != null) { sqlSession.close(); } if(is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } //7.返回结果 return result; } @Override public Integer delete(Integer id) { Integer result = null; SqlSession sqlSession = null; InputStream is = null; try{ //1.加载核心配置文件 is = Resources.getResourceAsStream("MyBatisConfig.xml"); //2.获取SqlSession工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); //3.通过工厂对象获取SqlSession对象 sqlSession = sqlSessionFactory.openSession(true); //4.获取StudentMapper接口的实现类对象 StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // StudentMapper mapper = new StudentMapperImpl(); //5.通过实现类对象调用方法,接收结果 result = mapper.delete(id); } catch (Exception e) { } finally { //6.释放资源 if(sqlSession != null) { sqlSession.close(); } if(is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } //7.返回结果 return result; } }
- 最后测试:通过StudentController的测试类来直接测试,能够测试通过即可
6.3 源码分析
-
分析动态代理对象如何生成的?
-
通过动态代理开发模式,我们只编写一个接口,不写实现类,我们通过 getMapper() 方法最终获取到 org.apache.ibatis.binding.MapperProxy 代理对象,然后执行功能,
-
而这个代理对象正是 MyBatis 使用了 JDK 的动态代理技术,帮助我们生成了代理实现类对象。从而可以进行相关持久化操作。
-
跟踪getMapper方法,最终可以跟踪到如下代码:这个代码就是我们之前自己实现动态代理的代码:
-
-
分析方法是如何执行的?
-
分析过程:
-
跟踪mapper.insert方法,代码打断点,然后调试跟踪
-
代码执行到insert之后,进入方法的执行,然后就进入到了invoke方法(动态代理执行方法,都会执行invoke)
-
在invoke中调用了mapperMethod.execute()方法
-
这个方法中通过 switch 语句根据操作类型来判断是新增、修改、删除、查询操作,
-
最后一步回到了 MyBatis 最原生的 SqlSession 方式来执行增删改查
-
-
6.4 知识小结
-
接口代理方式可以让我们只编写接口即可,而实现类对象由 MyBatis 生成
-
实现规则 :
- 映射配置文件中的名称空间必须和 Dao 层接口的全类名相同
- 映射配置文件中的增删改查标签的 id 属性必须和 Dao 层接口的方法名相同
- 映射配置文件中的增删改查标签的 parameterType 属性必须和 Dao 层接口方法的参数相同
- 映射配置文件中的增删改查标签的 resultType 属性必须和 Dao 层接口方法的返回值相同
-
获取动态代理对象
- 获取动态代理对象 SqlSession 功能类中的 getMapper() 方法
七. 动态sql语句
7.1 动态sql语句概述
-
Mybatis 的映射文件中,前面我们的 SQL 都是比较简单的,
-
有些时候业务逻辑复杂时,我们的 SQL是动态变化的,此时在前面的学习中我们的 SQL 就不能满足要求了。
-
代码:
-
StudentMapper.xml增加多条件sql
<select id="selectCondition" resultType="student" parameterType="student"> select * from student where id=#{id} and name = #{name} and age = #{age} </select>
-
Mapper接口:增加多条件查询方法
//多条件查询 public abstract List<Student> selectCondition(Student stu);
-
测试类:
@Test public void selectCondition() throws Exception{ InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); SqlSession sqlSession = sqlSessionFactory.openSession(true); //获取StudentMapper接口的实现类对象 StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); Student stu = new Student(); stu.setId(2); stu.setName("李四"); stu.setAge(24); //调用实现类的方法,接收结果 List<Student> list = mapper.selectCondition(stu); //处理结果 for (Student student : list) { System.out.println(student); } sqlSession.close(); is.close(); }
-
3个条件结果正常。2个条件(将setAge屏蔽掉)结果:如果有一个参数没有传递,默认是null,这肯定查询不到数据
-
7.2 动态 SQL 之<if>
-
我们根据实体类的不同取值,使用不同的 SQL语句来进行查询。
-
比如在 id如果不为空时可以根据id查询,如果username 不同空时还要加入用户名作为条件。
-
这种情况在我们的多条件组合查询中经常会碰到。
-
我们需要动态sql标签where和if。
-
<where>
:条件标签,如果有动态条件,则使用该标签代替where关键字 -
<if>
:条件判断标签<if test="条件判断"> 拼接的查询条件 </if>
-
如下图:
<select id="selectCondition" resultType="student" parameterType="student"> select * from student <where> <if test="id != null"> id = #{id} </if> <if test="name != null"> AND name = #{name} <!--如果没有传递id,会不会直接是where and name=xxx,不会,mybatis会做特殊处理--> </if> <if test="age != null"> AND age = #{age} </if> </where> </select>
-
总结语法:
<where>:条件标签。如果有动态条件,则使用该标签代替 where 关键字。 <if>:条件判断标签。语法如下: <if test=“条件判断”> 拼接的查询条件 </if>
7.3 动态 SQL 之<foreach>
-
<foreach>
:循环遍历标签。适用于多个参数或者的关系<foreach collection="" open="" close="" item="" separator=""> 获取参数 </foreach>
-
属性
- collection:参数容器类型,(list-集合,array-数组)
- open:开始的SQL语句
- close:结束的SQL语句
- item:参数变量名
- separator:分隔符
-
增加映射配置:
<select id="selectByIds" resultType="student" parameterType="list"> <include refid="select"/> <where> <foreach collection="list" open="id IN (" close=")" item="id" separator=","> #{id} </foreach> </where> </select>
-
增加接口:
//根据多个id查询 public abstract List<Student> selectByIds(List<Integer> ids);
-
Test01中增加测试方法:
@Test public void selectByIds() throws Exception{ InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); SqlSession sqlSession = sqlSessionFactory.openSession(true); //获取StudentMapper接口的实现类对象 StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); List<Integer> ids = new ArrayList<>(); ids.add(1); ids.add(2); ids.add(3); //调用实现类的方法,接收结果 List<Student> list = mapper.selectByIds(ids); for (Student student : list) { System.out.println(student); } sqlSession.close(); is.close(); }
-
测试:给ids集合中增加1和2测试,然后再集合中增加3来测试,发现都可以
7.4 SQL片段抽取
-
我们发现在映射文件中的sql语句,有很多都有重复的部分,可以通过sql片段抽取:
-
Sql 中可将重复的 sql 提取出来,使用时用 include 引用即可,最终达到 sql 重用的目的
-
映射文件:
<mapper namespace="com.lichee.mapper.StudentMapper">
<!--抽取-->
<sql id="select" >SELECT * FROM student</sql>
<select id="selectAll" resultType="student">
<!--引用-->
<include refid="select"/>
</select>
<select id="selectById" resultType="student" parameterType="int">
<!--引用-->
<include refid="select"/> WHERE id = #{id}
</select>
<insert id="insert" parameterType="student">
INSERT INTO student VALUES (#{id},#{name},#{age})
</insert>
<update id="update" parameterType="student">
UPDATE student SET name = #{name},age = #{age} WHERE id = #{id}
</update>
<delete id="delete" parameterType="int">
DELETE FROM student WHERE id = #{id}
</delete>
<select id="selectCondition" resultType="student" parameterType="student">
<!--引用-->
<include refid="select"/>
<where>
<if test="id != null">
id = #{id}
</if>
<if test="name != null">
AND name = #{name}
</if>
<if test="age != null">
AND age = #{age}
</if>
</where>
</select>
<select id="selectByIds" resultType="student" parameterType="list">
<!--引用-->
<include refid="select"/>
<where>
<foreach collection="list" open="id IN (" close=")" item="id" separator=",">
#{id}
</foreach>
</where>
</select>
</mapper>
7.5 知识小结
- 动态SQL指的就是SQL语句可以根据条件或者参数的不同进行动态的变化。
<where>
:条件标签。<if>
:条件判断的标签。<foreach>
:循环遍历的标签。<sql>
:抽取SQL片段的标签。<include>
:引入SQL片段的标签。
八. 分页插件
8.1 分页插件介绍
- 分页可以将很多条结果进行分页显示
- 如果当前在第一页,则没有上一页。如果当前在最后一页,则没有下一页
- 需要明确当前是第几页,这一页中显示多少条结果
- MyBatis分页插件总结
- 在企业级开发中,分页也是一种常见的技术
- 而目前使用的 MyBatis 是不带分页功能的,如果想实现分页的功能,需要我们手动编写 LIMIT 语句
- 但是不同的数据库实现分页的 SQL 语句也是不同的,所以手写分页成本较高
- 这个时候就可以借助分页插件来帮助我们实现分页功能
- PageHelper:第三方分页助手。将复杂的分页操作进行封装,从而让分页功能变得非常简单
8.2 分页插件的使用
-
MyBatis可以使用第三方的插件来对功能进行扩展,分页助手PageHelper是将分页的复杂操作进行封装,使用简单的方式即可获得分页的相关数据
-
开发步骤:
-
①导入与PageHelper的jar包
-
②在mybatis核心配置文件中配置PageHelper插件
<!-- 注意:分页助手的插件 配置在通用mapper之前 。 interceptor:拦截器,插件都是以拦截器形式实现的 -->
<plugin interceptor="com.github.pagehelper.PageHelper">
<!-- 指定方言 -->
<property name="dialect" value="mysql"/>
<!-- 其实就是指定到底是哪种sql语句,每种数据库的sql语句都有些许区别,所以可以理解为都有自己的方言-->
</plugin>
- ③测试:
public class Test01 {
@Test
public void selectPaging() throws Exception{
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//通过分页助手来实现分页功能 startPage参数1:当前页码,参数2:每页显示几条
// 第一页:显示3条数据 pageNum,pageSize
//PageHelper.startPage(1,3);
// 第二页:显示3条数据
//PageHelper.startPage(2,3);
// 第三页:显示3条数据
PageHelper.startPage(3,3);
//调用实现类的方法,接收结果
List<Student> list = mapper.selectAll();
for (Student student : list) {
System.out.println(student);
}
sqlSession.close();
is.close();
}
}
8.3 分页插件的参数获取
-
PageInfo:封装分页相关参数的功能类
-
核心方法:
返回值 方法名 说明 long getTotal() 获取总条数 int getPages() 获取总页数 int getPageNum() 获取当前页 int getPageSize() 获取每页显示条数 int getPrePage() 获取上一页 int getNextPage() 获取下一页 boolean isIsFirstPage() 获取是否是第一页 boolean isIsLastPage() 获取是否是最后一页 -
测试:修改Test01代码,在释放资源之前,增加如下代码:
//其他分页的数据 PageInfo<User> pageInfo = new PageInfo<User>(select); System.out.println("总条数:"+pageInfo.getTotal()); System.out.println("总页数:"+pageInfo.getPages()); System.out.println("当前页:"+pageInfo.getPageNum()); System.out.println("每页显示长度:"+pageInfo.getPageSize()); System.out.println("是否第一页:"+pageInfo.isIsFirstPage()); System.out.println("是否最后一页:"+pageInfo.isIsLastPage());
8.4 分页插件知识小结
- 分页:可以将很多条结果进行分页显示
-
分页插件 jar 包: pagehelper-5.1.10.jar 、 jsqlparser-3.1.jar
-
<plugins>
:集成插件标签 -
分页助手相关 API
- PageHelper:分页助手功能类:
- startPage():设置分页参数
- PageInfo:分页相关参数功能类:
- getTotal():获取总条数
- getPages():获取总页数
- getPageNum():获取当前页
- getPageSize():获取每页显示条数
- getPrePage():获取上一页
- getNextPage():获取下一页
- isIsFirstPage():获取是否是第一页
- isIsLastPage():获取是否是最后一页
- PageHelper:分页助手功能类:
九.MyBatis的多表操作
9.1 多表模型介绍
-
多表模型分类
- 一对一:在任意一方建立外键,关联对方的主键
- 一对多:在多的一方建立外键,关联一的一方的主键
- 多对多:借助中间表,中间表至少两个字段,分别关联两张表的主键
9.2 多表模型一对一操作
-
一对一模型: 人和身份证,一个人只有一个身份证
-
代码实现
-
sql语句准备
CREATE TABLE person( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20), age INT ); INSERT INTO person VALUES (NULL,'张三',23); INSERT INTO person VALUES (NULL,'李四',24); INSERT INTO person VALUES (NULL,'王五',25); CREATE TABLE card( id INT PRIMARY KEY AUTO_INCREMENT, number VARCHAR(30), pid INT, CONSTRAINT cp_fk FOREIGN KEY (pid) REFERENCES person(id) ); INSERT INTO card VALUES (NULL,'12345',1); INSERT INTO card VALUES (NULL,'23456',2); INSERT INTO card VALUES (NULL,'34567',3);
-
jdbc.properties
driver=com.mysql.jdbc.Driver url=jdbc:mysql://127.0.0.1:3306/db2 username=root password=root
-
MyBatisConfig.xml
<?xml version="1.0" encoding="UTF-8" ?> <!--MyBatis的DTD约束--> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <!--configuration 核心根标签--> <configuration> <!--引入数据库连接的配置文件--> <properties resource="jdbc.properties"/> <!--配置LOG4J--> <settings> <setting name="logImpl" value="log4j"/> </settings> <!--起别名--> <typeAliases> <package name="com.lichee.bean"/> </typeAliases> <!--environments配置数据库环境,环境可以有多个。default属性指定使用的是哪个--> <environments default="mysql"> <!--environment配置数据库环境 id属性唯一标识--> <environment id="mysql"> <!-- transactionManager事务管理。 type属性,采用JDBC默认的事务--> <transactionManager type="JDBC"></transactionManager> <!-- dataSource数据源信息 type属性 连接池--> <dataSource type="POOLED"> <!-- property获取数据库连接的配置信息 --> <property name="driver" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> </dataSource> </environment> </environments> <!-- mappers引入映射配置文件 --> <mappers> </mappers> </configuration>
-
log4j.properties
# Global logging configuration # ERROR WARN INFO DEBUG log4j.rootLogger=DEBUG, stdout # Console output... log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
-
-
javabean:Card
public class Card { private Integer id; //主键id private String number; //身份证号 private Person p; //所属人的对象 在表中是外键pid:人id,但是在javabean中一般都是外键对应的实体类javabean //Constructor //Getter and Setter //toString }
-
javabean:Person
public class Person { private Integer id; //主键id private String name; //人的姓名 private Integer age; //人的年龄 //Constructor //Getter and Setter //toString }
-
配置文件:新建com.lichee.one_to_one.OneToOneMapper.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.lichee.table01.OneToOneMapper"> <!--配置字段和实体对象属性的映射关系 type指定要配置的实体对象是哪个:card --> <resultMap id="oneToOne" type="card"> <!--id配置主键列:将sql中查询的cid列与card实体类中的id进行关联 --> <id column="cid" property="id" /> <!--result配置非主键列--> <result column="number" property="number" /> <!-- association:配置被包含对象的映射关系 property:被包含对象的变量名(属性名,在Card实体类中有一个p属性) javaType:被包含对象的数据类型(直接给person别名,因为我们通过typeAliases统一设置了bean包下所有实体类的别名了) --> <association property="p" javaType="person"> <id column="pid" property="id" /> <result column="name" property="name" /> <result column="age" property="age" /> </association> </resultMap> <!--resultMap属性指定的是resultMap标签的id 查询出来的结果涉及到两张表,所以不能使用resultType了 --> <select id="selectAll" resultMap="oneToOne"> SELECT c.id cid,number,pid,NAME,age FROM card c,person p WHERE c.pid=p.id </select> </mapper>
-
MyBatisConfig.xml中配置映射文件:
<mappers> <mapper resource="com/lichee/one_to_one/OneToOneMapper.xml"/> </mappers>
-
接口:com.lichee.table01.OneToOneMapper
public interface OneToOneMapper { //查询全部 public abstract List<Card> selectAll(); }
- 测试类:
public class Test01 { @Test public void selectAll() throws Exception{ InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); SqlSession sqlSession = sqlSessionFactory.openSession(true); OneToOneMapper mapper = sqlSession.getMapper(OneToOneMapper.class); List<Card> list = mapper.selectAll(); for (Card c : list) { System.out.println(c); } sqlSession.close(); is.close(); } }
-
一对一配置总结:
<resultMap>:配置字段和对象属性的映射关系标签。
id 属性:唯一标识
type 属性:实体对象类型
<id>:配置主键映射关系标签。
<result>:配置非主键映射关系标签。
column 属性:表中字段名称
property 属性: 实体对象变量名称
<association>:配置被包含对象的映射关系标签。
property 属性:被包含对象的变量名
javaType 属性:被包含对象的数据类型
9.3 多表模型一对多操作
-
一对多模型: 一对多模型:班级和学生,一个班级可以有多个学生
-
代码实现
- sql语句准备
CREATE TABLE classes( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20) ); INSERT INTO classes VALUES (NULL,'黑马一班'); INSERT INTO classes VALUES (NULL,'黑马二班'); CREATE TABLE student( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(30), age INT, cid INT, CONSTRAINT cs_fk FOREIGN KEY (cid) REFERENCES classes(id) ); INSERT INTO student VALUES (NULL,'张三',23,1); INSERT INTO student VALUES (NULL,'李四',24,1); INSERT INTO student VALUES (NULL,'王五',25,2); INSERT INTO student VALUES (NULL,'赵六',26,2);
- 新建javabean:Classes
public class Classes { private Integer id; //主键id private String name; //班级名称 private List<Student> students; //班级中所有学生对象 一个班级里多个学生 //Constructor //Getter and Setter //toString }
- javabean:Student
public class Student { private Integer id; //主键id private String name; //学生姓名 private Integer age; //学生年龄 //Constructor //Getter and Setter //toString }
- 配置文件:com.lichee.one_to_many.OneToManyMapper.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.lichee.table02.OneToManyMapper"> <resultMap id="oneToMany" type="classes"> <id column="cid" property="id"/> <result column="cname" property="name"/> <!-- collection:配置被包含的集合对象映射关系(如果被包含的对象是多的一方,需要用collection) property:被包含对象的变量名 ofType:被包含对象的实际数据类型(collection标签中指定被包含对象类型用的是ofType) --> <collection property="students" ofType="student"> <id column="sid" property="id"/> <result column="sname" property="name"/> <result column="sage" property="age"/> </collection> </resultMap> <select id="selectAll" resultMap="oneToMany"> SELECT c.id cid,c.name cname,s.id sid,s.name sname,s.age sage FROM classes c,student s WHERE c.id=s.cid </select> </mapper>
- 配置映射文件
<mappers> <mapper resource="com/lichee/one_to_one/OneToOneMapper.xml"/> <mapper resource="com/lichee/one_to_many/OneToManyMapper.xml"/> </mappers>
- 接口
public interface OneToManyMapper { //查询全部 public abstract List<Classes> selectAll(); }
- 测试类com.lichee.table02.Test01
public class Test01 { @Test public void selectAll() throws Exception{ InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); SqlSession sqlSession = sqlSessionFactory.openSession(true); OneToManyMapper mapper = sqlSession.getMapper(OneToManyMapper.class); List<Classes> classes = mapper.selectAll(); for (Classes cls : classes) { System.out.println(cls.getId() + "," + cls.getName()); List<Student> students = cls.getStudents(); for (Student student : students) { System.out.println("\t" + student); } } sqlSession.close(); is.close(); } }
-
一对多配置文件总结:
<resultMap>:配置字段和对象属性的映射关系标签。
id 属性:唯一标识
type 属性:实体对象类型
<id>:配置主键映射关系标签。
<result>:配置非主键映射关系标签。
column 属性:表中字段名称
property 属性: 实体对象变量名称
<collection>:配置被包含集合对象的映射关系标签。
property 属性:被包含集合对象的变量名
ofType 属性:集合中保存的对象数据类型
9.4 多表模型多对多操作
-
多对多模型:学生和课程,一个学生可以选择多门课程、一个课程也可以被多个学生所选择
-
代码实现
- sql语句准备
CREATE TABLE course( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20) ); INSERT INTO course VALUES (NULL,'语文'); INSERT INTO course VALUES (NULL,'数学'); CREATE TABLE stu_cr( id INT PRIMARY KEY AUTO_INCREMENT, sid INT, cid INT, CONSTRAINT sc_fk1 FOREIGN KEY (sid) REFERENCES student(id), CONSTRAINT sc_fk2 FOREIGN KEY (cid) REFERENCES course(id) ); INSERT INTO stu_cr VALUES (NULL,1,1); INSERT INTO stu_cr VALUES (NULL,1,2); INSERT INTO stu_cr VALUES (NULL,2,1); INSERT INTO stu_cr VALUES (NULL,2,2);
- Javabean
public class Course { private Integer id; //主键id private String name; //课程名称 //Constructor //Getter and Setter //toString }
- 修改:Student
private List<Course> courses; // 学生所选择的课程集合 public Student(Integer id, String name, Integer age, List<Course> courses) { this.id = id; this.name = name; this.age = age; this.courses = courses; } public List<Course> getCourses() { return courses; } public void setCourses(List<Course> courses) { this.courses = courses; }
-
我们这里只是多表查询,不做其他操作,所以中间表不需要对应的实体类
-
配置文件
<?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.lichee.table03.ManyToManyMapper"> <resultMap id="manyToMany" type="student"> <id column="sid" property="id"/> <result column="sname" property="name"/> <result column="sage" property="age"/> <collection property="courses" ofType="course"> <id column="cid" property="id"/> <result column="cname" property="name"/> </collection> </resultMap> <select id="selectAll" resultMap="manyToMany"> SELECT sc.sid,s.name sname,s.age sage,sc.cid,c.name cname FROM student s,course c,stu_cr sc WHERE sc.sid=s.id AND sc.cid=c.id </select> <!--注意这里查询的是sc.cid,将这个cid给course的id了,这也是可以的,因为都是课程id 但其实sql语句中的sc.cid,可以换成c.id,这样的话给course的id更合适 --> </mapper>
- 配置
<mappers> <mapper resource="com/lichee/one_to_one/OneToOneMapper.xml"/> <mapper resource="com/lichee/one_to_many/OneToManyMapper.xml"/> <mapper resource="com/lichee/many_to_many/ManyToManyMapper.xml"/> </mappers>
- 接口
public interface ManyToManyMapper { //查询全部 public abstract List<Student> selectAll(); }
- 测试类
public class Test01 { @Test public void selectAll() throws Exception{ InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); SqlSession sqlSession = sqlSessionFactory.openSession(true); ManyToManyMapper mapper = sqlSession.getMapper(ManyToManyMapper.class); List<Student> students = mapper.selectAll(); for (Student student : students) { System.out.println(student.getId() + "," + student.getName() + "," + student.getAge()); List<Course> courses = student.getCourses(); for (Course cours : courses) { System.out.println("\t" + cours); } } sqlSession.close(); is.close(); } }
-
多对多配置文件总结:
<resultMap>:配置字段和对象属性的映射关系标签。
id 属性:唯一标识
type 属性:实体对象类型
<id>:配置主键映射关系标签。
<result>:配置非主键映射关系标签。
column 属性:表中字段名称
property 属性: 实体对象变量名称
<collection>:配置被包含集合对象的映射关系标签。
property 属性:被包含集合对象的变量名
ofType 属性:集合中保存的对象数据类型
9.5 多表模型操作总结
- 多表模型分析:一对一、一对多、多对多。
<resultMap>
:配置字段和对象属性的映射关系标签。- id属性:唯一标识
- type属性:实体对象类型
<id>
:配置主键映射关系标签。<result>
:配置非主键映射关系标签- column属性:表中字段名称
- property属性:实体对象变量名称
<association>
:配置被包含对象的映射关系标签。- property属性:被包含对象变量名称
- javaType属性:被包含对象的数据类型
<collection>
:配置被包含集合对象的映射关系映射。- property属性:被包含集合对象变量名称
- ofType属性:集合中保存的对象数据类型
十.Mybatis注解开发单表操作
10.1 MyBatis的常用注解
-
常用注解
-
@Select(“查询的 SQL 语句”):执行查询操作注解
-
@Insert(“查询的 SQL 语句”):执行新增操作注解
-
@Update(“查询的 SQL 语句”):执行修改操作注解
-
@Delete(“查询的 SQL 语句”):执行删除操作注解
-
10.2 注解实现查询操作
-
javabean
public class Student { private Integer id; private String name; private Integer age; //Constructor //Getter and Setter //toString }
-
创建mapper接口
public interface StudentMapper { //查询全部 @Select("SELECT * FROM student") public abstract List<Student> selectAll(); }
-
配置MyBatisConfig.xml
<!--配置映射关系:这里已经没有Mapper映射文件了,但是我们需要配置mapper接口所在的包--> <mappers> <package name="com.lichee.mapper"/> </mappers> <!--其实是注解的方式帮助我们生成了映射文件,所以我们依然是在mappers节点里配置-->
-
测试类:
@Test public void selectAll() throws Exception{ InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); SqlSession sqlSession = sqlSessionFactory.openSession(true); StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); List<Student> list = mapper.selectAll(); for (Student student : list) { System.out.println(student); } sqlSession.close(); is.close(); }
-
注意:
- 修改MyBatis的核心配置文件,我们使用了注解替代的映射文件,所以我们只需要加载使用了注解的Mapper接口即可
<mappers> <!--扫描使用注解的类--> <mapper class="com.lichee.mapper.UserMapper"></mapper> </mappers>
- 或者指定扫描包含映射关系的接口所在的包也可以
<mappers> <!--扫描使用注解的类所在的包--> <package name="com.lichee.mapper"></package> </mappers>
10.3 注解实现新增操作
-
StudentMapper新增接口方法
//新增操作: sql的参数与之前的写法一致,从insert方法的参数中获取对应属性值 @Insert("INSERT INTO student VALUES (#{id},#{name},#{age})") public abstract Integer insert(Student stu);
-
测试方法
@Test public void insert() throws Exception{ InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); SqlSession sqlSession = sqlSessionFactory.openSession(true); StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); Student stu = new Student(4,"赵六",26); Integer result = mapper.insert(stu); System.out.println(result); sqlSession.close(); is.close(); }
10.4 注解实现修改操作
-
StudentMapper新增接口方法
//修改操作 @Update("UPDATE student SET name=#{name},age=#{age} WHERE id=#{id}") public abstract Integer update(Student stu);
-
测试方法
@Test public void update() throws Exception{ InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); SqlSession sqlSession = sqlSessionFactory.openSession(true); StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); Student stu = new Student(4,"赵六",36); Integer result = mapper.update(stu); System.out.println(result); sqlSession.close(); is.close(); }
10.5 注解实现删除操作
-
StudentMapper新增接口方法
//删除操作 @Delete("DELETE FROM student WHERE id=#{id}") public abstract Integer delete(Integer id);
-
测试方法
@Test public void delete() throws Exception{ InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); SqlSession sqlSession = sqlSessionFactory.openSession(true); StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); Integer result = mapper.delete(4); System.out.println(result); sqlSession.close(); is.close(); }
10.6 注解开发总结
注解可以简化开发操作,省略映射配置文件的编写
-
常用注解
@Select(“查询的 SQL 语句”):执行查询操作注解
@Insert(“查询的 SQL 语句”):执行新增操作注解
@Update(“查询的 SQL 语句”):执行修改操作注解
@Delete(“查询的 SQL 语句”):执行删除操作注解
-
配置映射关系
<mappers> <package name="接口所在包"/> </mappers>
十一.MyBatis注解开发的多表操作
11.1 MyBatis的注解实现复杂映射开发
-
实现复杂关系映射之前我们可以在映射文件中通过配置
<resultMap>
来实现, -
使用注解开发后,我们可以使用@Results注解,@Result注解,@One注解,@Many注解组合完成复杂关系的配置
注解 说明 @Results 代替的是标签 <resultMap>
该注解中可以使用单个@Result注解,也可以使用@Result集合。
使用格式:@Results ({@Result () ,@Result()})或@Results (@Result () )@Result 代替了 <id>
标签和<result>
标签
@Result中属性介绍:
column:数据库的列名
property:需要装配的属性名
one:需要使用的@One注解(@Result (one=@One) ( ) ) )
many:需要使用的@Many注解(@Result (many=@many) ( ) ) )@One(一对一) 代替了 <assocation>
标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
@One注解属性介绍:
select:指定用来多表查询的 sqlmapper
使用格式:@Result(column=" “,property=”",one=@One(select=""))@Many(多对一) 代替了 <collection>
标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。
使用格式:@Result(property="",column="",many=@Many(select=""))
11.2 一对一查询
11.2.0 准备工作
-
javabean - card
public class Card { private Integer id; //主键id private String number; //身份证号 private Person p; //所属人的对象 //Constructor //Getter and Setter //toString }
-
javabean - person
public class Person { private Integer id; //主键id private String name; //人的姓名 private Integer age; //人的年龄 //Constructor //Getter and Setter //toString }
-
cardMapper接口:我们的核心就是要在Card中做一些处理,实现一对一的查询
public interface CardMapper { //查询全部 public abstract List<Card> selectAll(); }
11.2.1 一对一查询的模型
一对一查询的需求:查询一个用户信息,与此同时查询出该用户对应的身份证信息
11.2.2 一对一查询的语句
对应的sql语句:
SELECT * FROM card; -- 只根据这个sql语句只能查询出来card的数据
SELECT * FROM person WHERE id=#{id}; -- 需要根据card表中查询出来的pid,再次查询person数据才能将person数据也查询出来
11.2.3 创建PersonMapper接口
public interface PersonMapper {
//根据id查询
@Select("SELECT * FROM person WHERE id=#{id}")
public abstract Person selectById(Integer id);
}
11.2.4 使用注解配置CardMapper
public interface CardMapper {
//查询全部
@Select("SELECT * FROM card")
@Results({
@Result(column = "id",property = "id"),
@Result(column = "number",property = "number"),
@Result(
property = "p", // 被包含对象的变量名
javaType = Person.class, // 被包含对象的实际数据类型
column = "pid", // 根据查询出的card表中的pid字段来查询person表
/*
one、@One 一对一固定写法
select属性:指定调用哪个接口中的哪个方法
*/
one = @One(select = "com.lichee.one_to_one.PersonMapper.selectById")
)
})
public abstract List<Card> selectAll();
}
2.2.5 测试类
public class Test01 {
@Test
public void selectAll() throws Exception{
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
CardMapper mapper = sqlSession.getMapper(CardMapper.class);
List<Card> list = mapper.selectAll();
for (Card card : list) {
System.out.println(card);
}
sqlSession.close();
is.close();
}
}
11.2.6 一对一配置总结
@Results:封装映射关系的父注解。
Result[] value():定义了 Result 数组
@Result:封装映射关系的子注解。
column 属性:查询出的表中字段名称
property 属性:实体对象中的属性名称
javaType 属性:被包含对象的数据类型
one 属性:一对一查询固定属性
@One:一对一查询的注解。
select 属性:指定调用某个接口中的方法
11.3 一对多查询
11.3.1 一对多查询的模型
一对多查询的需求:查询一个课程,与此同时查询出该该课程对应的学生信息
11.3.2 一对多查询的语句
对应的sql语句:
SELECT * FROM classes
SELECT * FROM student WHERE cid=#{cid}
11.3.3 创建StudentMapper接口
public interface StudentMapper {
//根据cid查询student表
@Select("SELECT * FROM student WHERE cid=#{cid}")
public abstract List<Student> selectByCid(Integer cid);
}
11.3.4 使用注解配置Mapper
public interface ClassesMapper {
//查询全部
@Select("SELECT * FROM classes")
@Results({
@Result(column = "id",property = "id"),
@Result(column = "name",property = "name"),
@Result(
property = "students", // 被包含对象的变量名
javaType = List.class, // 被包含对象的实际数据类型
column = "id", // 根据查询出的classes表的id字段来查询student表
/*
many、@Many 一对多查询的固定写法
select属性:指定调用哪个接口中的哪个查询方法
*/
many = @Many(select = "com.lichee.one_to_many.StudentMapper.selectByCid")
)
})
public abstract List<Classes> selectAll();
}
11.3.5 测试类
public class Test01 {
@Test
public void selectAll() throws Exception{
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
ClassesMapper mapper = sqlSession.getMapper(ClassesMapper.class);
List<Classes> list = mapper.selectAll();
for (Classes cls : list) {
System.out.println(cls.getId() + "," + cls.getName());
List<Student> students = cls.getStudents();
for (Student student : students) {
System.out.println("\t" + student);
}
}
sqlSession.close();
is.close();
}
}
11.3.6 一对多配置总结
@Results:封装映射关系的父注解。
Result[] value():定义了 Result 数组
@Result:封装映射关系的子注解。
column 属性:查询出的表中字段名称
property 属性:实体对象中的属性名称
javaType 属性:被包含对象的数据类型
many 属性:一对多查询固定属性
@Many:一对多查询的注解。
select 属性:指定调用某个接口中的方法
11.4 多对多查询
11.4.1 多对多查询的模型
多对多查询的需求:查询学生以及所对应的课程信息
11.4.2 多对多查询的语句
对应的sql语句:
SELECT DISTINCT s.id,s.name,s.age FROM student s,stu_cr sc WHERE sc.sid=s.id
SELECT c.id,c.name FROM stu_cr sc,course c WHERE sc.cid=c.id AND sc.sid=#{id}
11.4.3 添加CourseMapper 接口方法
public interface CourseMapper {
//根据学生id查询所选课程
@Select("SELECT c.id,c.name FROM stu_cr sc,course c WHERE sc.cid=c.id AND sc.sid=#{id}")
public abstract List<Course> selectBySid(Integer id);
}
11.4.4 使用注解配置Mapper
public interface StudentMapper {
//查询全部
@Select("SELECT DISTINCT s.id,s.name,s.age FROM student s,stu_cr sc WHERE sc.sid=s.id")
@Results({
@Result(column = "id",property = "id"),
@Result(column = "name",property = "name"),
@Result(column = "age",property = "age"),
@Result(
property = "courses", // 被包含对象的变量名
javaType = List.class, // 被包含对象的实际数据类型
column = "id", // 根据查询出student表的id来作为关联条件,去查询中间表和课程表
/*
many、@Many 一对多查询的固定写法
select属性:指定调用哪个接口中的哪个查询方法
*/
many = @Many(select = "com.lichee.many_to_many.CourseMapper.selectBySid")
)
})
public abstract List<Student> selectAll();
}
11.4.5 测试类
public class Test01 {
@Test
public void selectAll() throws Exception{
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> list = mapper.selectAll();
for (Student student : list) {
System.out.println(student.getId() + "," + student.getName() + "," + student.getAge());
List<Course> courses = student.getCourses();
for (Course cours : courses) {
System.out.println("\t" + cours);
}
}
sqlSession.close();
is.close();
}
}
11.4.6 多对多配置总结
@Results:封装映射关系的父注解。
Result[] value():定义了 Result 数组
@Result:封装映射关系的子注解。
column 属性:查询出的表中字段名称
property 属性:实体对象中的属性名称
javaType 属性:被包含对象的数据类型
many 属性:一对多查询固定属性
@Many:一对多查询的注解。
select 属性:指定调用某个接口中的方法
十二.构建sql
12.1 SQL 构建对象介绍
-
我们之前通过注解开发时,相关 SQL 语句都是自己直接拼写的。一些关键字写起来比较麻烦、而且容易出错。
-
MyBatis 给我们提供了 org.apache.ibatis.jdbc.SQL 功能类,专门用于构建 SQL 语句
方法名 说明 SELECT(String.column) 根据字段拼接查询语句 FROM(String…table) 根据表名拼接语句 WHERE(String…condition) 根据条件拼接语句 INSERT_INTO(String table) 根据表名拼接新增语句 VALUES(String column,String values) 根据字段和值拼接插入数据语句 UPDATE(String table) 根据表名拼接修改语句 DELETE_FROM(String table) 根据表名拼接删除语句 … … … … -
新建测试类:
public class SqlTest { public static void main(String[] args) { String sql = getSql(); System.out.println(sql); } //定义方法,获取查询student表的sql语句 public static String getSql() { String sql = "SELECT * FROM student"; return sql; } }
- 如果sql语句比较长,sql中的关键字较多时,就可能会写错
-
修改代码:使用SQL类通过的方法来编写sql语句
public class SqlTest { public static void main(String[] args) { String sql = getSql(); System.out.println(sql); } public static String getSql() { String sql = new SQL(){//通过SQL类提供的方法来实现sql语句的编写 { SELECT("*"); FROM("student"); } }.toString(); return sql; } }
12.2 查询功能的实现
-
定义功能类并提供获取查询的 SQL 语句的方法
- 新建类:ReturnSql,定义获取sql语句的方法
public class ReturnSql { //定义方法,返回查询的sql语句 public String getSelectAll() { return new SQL() { { SELECT("*"); FROM("student"); } }.toString(); } }
-
之前是在Mapper接口中直接通过注解(@Select,@Insert等)来设置的sql
-
现在有提供了sql语句的方法,通过@SelectProvider注解来获取
-
@SelectProvider:生成查询用的 SQL 语句注解(调用提供sql语句的方法,获取到查询的sql语句)
-
type 属性:用于指定生成 SQL 语句功能的类对象
- method 属性:用于指定类中要执行获取sql语句的方法 (指定方法名,不加小括号)
-
修改StudentMapper
//查询全部 //@Select("SELECT * FROM student") //注意:method只是指定一个方法的名字,SelectProvider内部会自己调用 @SelectProvider(type = ReturnSql.class , method = "getSelectAll") public abstract List<Student> selectAll();
-
运行test包中的Test01的selectAll方法,能查询出数据即可
12.3 新增功能的实现
-
定义功能类并提供获取新增的 SQL 语句的方法,在ReturnSql中增加如下方法:
//定义方法,返回新增的sql语句 public String getInsert(Student stu) { return new SQL() { { INSERT_INTO("student"); INTO_VALUES("#{id},#{name},#{age}"); } }.toString(); }
-
@InsertProvider:生成新增用的 SQL 语句注解(调用提供sql语句的方法,获取到新增的sql语句)
-
type 属性:生成 SQL 语句功能类对象
- method 属性:指定调用方法
-
-
修改StudentMapper
//新增功能 //@Insert("INSERT INTO student VALUES (#{id},#{name},#{age})") @InsertProvider(type = ReturnSql.class , method = "getInsert") public abstract Integer insert(Student stu);
-
运行test包中的Test01的insert方法,能插入数据即可
12.4 修改功能的实现
-
定义功能类并提供获取修改的 SQL 语句的方法
//定义方法,返回修改的sql语句 public String getUpdate(Student stu) { return new SQL() { { UPDATE("student"); SET("name=#{name}","age=#{age}"); WHERE("id=#{id}"); } }.toString(); }
-
@UpdateProvider:生成修改用的 SQL 语句注解(调用提供sql语句的方法,获取到更新的sql语句)
-
type 属性:生成 SQL 语句功能类对象
- method 属性:指定调用方法
-
-
修改StudentMapper
//修改功能 //@Update("UPDATE student SET name=#{name},age=#{age} WHERE id=#{id}") @UpdateProvider(type = ReturnSql.class , method = "getUpdate") public abstract Integer update(Student stu);
-
运行test包中的Test01的update方法,能更新数据即可
12.5 删除功能的实现
-
定义功能类并提供获取删除的 SQL 语句的方法
//定义方法,返回删除的sql语句 public String getDelete(Integer id) { return new SQL() { { DELETE_FROM("student"); WHERE("id=#{id}"); } }.toString(); }
-
@DeleteProvider:生成删除用的 SQL 语句注解(调用提供sql语句的方法,获取到删除的sql语句)
-
type 属性:生成 SQL 语句功能类对象
- method 属性:指定调用方法
-
-
修改StudentMapper
//删除功能 //@Delete("DELETE FROM student WHERE id=#{id}") @DeleteProvider(type = ReturnSql.class , method = "getDelete") public abstract Integer delete(Integer id);
-
运行test包中的Test01的delete方法,能删除数据即可