一、Mybatis
1、简介
MyBatis 是一款优秀的持久层框架;它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
2、优点
1、简单易学
mybatis本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
2、灵活
mybatis不会对应用程序或者数据库的现有设计强加任何影响。sql写在xml里,便于统一管理和优化。通过sql基本上可以实现我们不使用数据访问框架可以实现的所有功能,或许更多。
3、解除sql与程序代码的耦合
通过提供DAL层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
4、提供映射标签,支持对象与数据库的orm字段关系映射
5、提供对象关系映射标签,支持对象关系组建维护
6、提供xml标签,支持编写动态sql。
3、缺点
1、编写SQL语句时工作量很大,尤其是字段多、关联表多时,更是如此。
2、SQL语句依赖于数据库,导致数据库移植性差,不能更换数据库。
3、框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改。
4、二级缓存机制不佳。
二、Mybatis操作
创建数据库及数据表
1、Mybatis原生使用
pom.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>Mybatis_proto</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Mybatis_proto</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>mybatis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<!-- 定义classpath -->
<resources>
<!-- resources文件 -->
<resource>
<directory>src/main/resources</directory>
<!-- 是否被过滤,如果被过滤则无法使用 -->
<filtering>false</filtering>
</resource>
<!-- java文件夹 -->
<resource>
<directory>src/main/java</directory>
<!-- 引入映射文件等 -->
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
</build>
</project>
写 SQL 的 mapper 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.example.mybatis_proto.mapper.UserMapper">
<select id="selectUser" resultType="com.example.mybatis_proto.entity.User" parameterType="com.example.mybatis_proto.entity.User">
select * from springsemester where id = #{id}
</select>
</mapper>
Mapper 接口类,结合使用了 @Select
/**
* UserMapper 接口,映射对数据库的操作
*/
public interface UserMapper {
public User selectUser(int id);
@Select("select * from springsemester")
public List<User> selectAllUsers();
}
User实体类
/**
* @author DF10F-0001A
*/
public class User {
private int id;
private String name;
private int age;
private String dapartment;
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", dapartment='" + dapartment + '\'' +
'}';
}
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;
}
public String getDapartment() {
return dapartment;
}
public void setDapartment(String dapartment) {
this.dapartment = dapartment;
}
}
启动类MybatisProtoApplication
/**
* 测试 Mybatis xml 与 注解的使用
* @author DF10F-0001A
*/
public class MybatisProtoApplication {
public static void main(String[] args) throws IOException {
testJavaConfig();
}
/**
* 测试 Java 方式
*/
private static void testJavaConfig() {
// 创建数据源
DataSource dataSource = new PooledDataSource("com.mysql.jdbc.Driver",
"jdbc:mysql://127.0.0.1:3306/springsemester?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8",
"root",
"123456");
//事务
TransactionFactory transactionFactory = new JdbcTransactionFactory();
//环境
Environment environment = new Environment("development", transactionFactory, dataSource);
//配置
Configuration configuration = new Configuration(environment);
//注册
configuration.addMapper(UserMapper.class);
SqlSessio nFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//查询所有 user 数据
List<User> users = userMapper.selectAllUsers();
System.out.println(users);
//关闭 SqlSession
sqlSession.close();
}
}
2、Mybatis开发方式
(1)、mapper代理对象 + xml
使用动态代理机制,dao层接口化,底层自动创建代理对象代替dao对象创建SqlSession,并且自动与xml文件进行sql配对。
UserDao.java
public class User implements Serializable {
private int id;
private String name;
private int age;
private String dapartment;
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", dapartment='" + dapartment + '\'' +
'}';
}
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;
}
public String getDapartment() {
return dapartment;
}
public void setDapartment(String dapartment) {
this.dapartment = dapartment;
}
}
SqlMapConfig.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="mysql">
<!-- 配置mysql的环境 -->
<environment id="mysql">
<!-- 配置事务的类型 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置数据源(连接池) -->
<dataSource type="POOLED">
<!-- 配置连接数据库的四个基本信息 -->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/springsemester"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 指定映射配置文件的位置 -->
<mappers>
<mapper resource="com/example/mybatis_xml/dao/InterfaceUserDao.xml"/>
</mappers>
</configuration>
InterfaceUserDao.java
/**
* UserMapper 接口,映射对数据库的操作
*/
public interface InterfaceUserDao {
/**
* 以查询所有为例,其他操作大同小异
*/
List<User> findAll();
}
InterfaceUserDao.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">
<!-- namespace是dao的全限定类名,定位的是InterfaceUserDao.java这个接口-->
<mapper namespace="com.example.mybatis_xml.dao.InterfaceUserDao">
<!-- 配置查询所有,通过namespace找到InterfaceUserDao.java,再通过id找到findAll()方法 ,resultType标签是该方法返回的结果类型,显然在这里返回的是User-->
<select id="findAll" resultType="com.example.mybatis_xml.entity.User">
select * from mybatis_xml;
</select>
</mapper>
MybatisProtoApplication
public class MybatisProtoApplication {
public static void main(String[] args) throws Exception {
// 1.读取配置文件
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2.创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);
// 3.使用工厂生产SqlSession对象
SqlSession session = factory.openSession();
// 4.使用SqlSession对象创建dao接口代理对象
InterfaceUserDao userDao = session.getMapper(InterfaceUserDao.class);
// 5.使用代理对象执行方法
List<User> listAll = userDao.findAll();
for (User user : listAll) {
System.out.println(user);
}
// 6.释放资源
session.close();
is.close();
}
}
(2)、mapper代理对象 + 注解
使用动态代理机制,dao层接口化,底层自动创建代理对象代替dao对象创建SqlSession,并且自动从注解中提取sql。
MyBatis的常用注解
-
@Insert:实现新增
-
@Update:实现更新
-
@Delete:实现删除
-
@Select:实现查询
-
@Result:实现结果集封装
-
@Results:可以与@Result 一起用,封装多个结果集
-
@One:实现一对一结果集封装
-
@Many:实现一对多结果集封装
编写实体类
@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
private int id;
private String name;
private int age;
private String dapartment;
}
UserMapper.java
/**
* @author DF10F-0001A
* @description: 基于注解开发的持久层接口
*/
public interface UserMapper {
/**
* 查询所有用户
*
* @return
*/
@Select("select * from mybatis_annotation")
List<User> findAll();
}
SqlMapConfig.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>
<!-- 配置别名的注册 -->
<typeAliases>
<package name="com.example.mybatis_annotation.entity"/>
</typeAliases>
<!-- 配置 mybatis 的环境 -->
<environments default="mysql">
<!-- 配置 mysql 的环境 -->
<environment id="mysql">
<!-- 配置事务的类型 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置连接数据库的信息:用的是数据源(连接池) -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/springsemester?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 配置映射信息 -->
<mappers>
<!-- 配置 dao 接口的位置,它有两种方式
第一种:使用 mapper 标签配置 class 属性
第二种:使用 package 标签,直接指定 dao 接口所在的包
-->
<package name="com.example.mybatis_annotation.mapper"/>
</mappers>
</configuration>
测试类
@SpringBootTest
public class MybatisAnnotationApplicationTests{
private InputStream in;
private SqlSessionFactory factory;
private SqlSession session;
private UserMapper userMapper;
@Before
public void init() throws Exception {
//1.读取配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
factory = builder.build(in);
//3.创建 session
session = factory.openSession();
//4.创建代理对象
userMapper = session.getMapper(UserMapper.class);
}
/**
* 测试查询所有
*/
@Test
public void testFindAll() {
List<User> users = userMapper.findAll();
for (User user : users) {
System.out.println(user);
}
}
3、使用Map
当实体类,或者数据库中的表,字段或者参数过多,我们应该考虑使用Map!
Map传递参数,直接在sql中取出key即可! 【parameter=“map”】
对象传递参数,直接在sql中取出对象的属性即可! 【parameter=“Object”】
只有一个基本类型参数的情况下,可以直接在sql中取到
多个参数用Map , 或者注解!
UserMapper接口
public void addUser(Map<String,Object> map);
UserMapper.xml
<!--对象中的属性可以直接取出来 传递map的key-->
<insert id="addUser2" parameterType="map">
insert into user (id,name,password) values (#{userid},#{username},#{userpassword})
</insert>
测试
@Test
public void test3(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("userid",4);
map.put("username","王虎");
map.put("userpassword",789);
mapper.addUser2(map);
//提交事务
sqlSession.commit();
//关闭资源
sqlSession.close();
}
4、模糊查询
Java代码执行的时候,传递通配符%
List<User> userList = mapper.getUserLike("%李%");
在sql拼接中使用通配符
select * from user where name like "%"#{value}"%"
三、配置解析
1、核心配置文件
MyBatis-config
<?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.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://172.31.32.184:3306/constxiong?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="constxiong@123"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="constxiong/mapper/UserMapper.xml"/>
</mappers>
</configuration>
-
environments-default属性表示在默认的情况下我们将启用的数据源
-
environment-id代表当前环境的唯一标识
transactionManager type="JDBC
在 MyBatis 中有两种事务管理器类型(也就是 type=”[JDBC|MANAGED]”):
-
JDBC – 这个配置直接简单使用了 JDBC 的提交和回滚设置。 它依赖于从数据源得 到的连接来管理事务范围。
-
MANAGED – 这个配置几乎没做什么。它从来不提交或回滚一个连接。而它会让 容器来管理事务的整个生命周期(比如 Spring 或 JEE 应用服务器的上下文) 默认 情况下它会关闭连接。 然而一些容器并不希望这样, 因此如果你需要从连接中停止 它,将 closeConnection 属性设置为 false。例如:
<transactionManagertype="MANAGED"> <propertyname="closeConnection"value="false"/></transactionManager>
dataSource type="POOLED"
在里面可以放入配置数据库的基本连接信息(driver,url,username,password)同时在该标签上有一个属性type,它表示mybatis获取连接的方式。type属性有三个值,分别为unPooled,pooled和JNDI。
property属性
在使用 properties 标签配置时,我们可以采用两种方式指定属性配置
第一种
<properties>
<property name="jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="jdbc.url" value="jdbc:mysql://localhost:3306/xxx"/>
<property name="jdbc.username" value="root"/>
<property name="jdbc.password" value="1234"/>
</properties>
第二种
在 classpath 下定义 db.properties 文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/springdb
jdbc.user=root
jdbc.passwd=123456
此时我们的 dataSource 标签就变成了引用上面的配置
<?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">
</properties>
<!-- 和spring整合后 environments配置将废除 -->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理,事务控制由mybatis -->
<transactionManager type="JDBC" />
<!-- 数据库连接池,由mybatis管理 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<!-- 加载 映射文件 -->
<mappers>
<mapper resource="User.xml" />
<mapper resource="UserMapper.xml" />
</mappers>
</configuration>
Mapper
第一种依据 Mapper 类 具体路径 配置 Mapper
<configuration>
<mappers>
<!-- class 级别的指定 -->
<mapper class="com.bestcxx.stu.springmvc.mapper.UserModelMapper"/>
<mapper class="com.bestcxx.stu.springmvc.mapper.UserModelTwoMapper"/>
</mappers>
</configuration>
文件结构:
第二种依据 Mapper 类所在的package包路径 配置 Mapper
<configuration>
<mappers>
<package name="com.bestcxx.stu.springmvc.mapper"/>
</mappers>
</configuration>
文件结构:
第三种是把 Mapper 的xml配置文件单独放置到 resources 中,和Mapper 类分开了
<configuration>
<mappers>
<!-- 使用这个方案,可以单独指定Mapper的位置 -->
<mapper resource="mybatis/mappings/UserModelMapper.xml"/>
<mapper resource="mybatis/mappings/UserModelTwoMapper.xml"/>
</mappers>
</configuration>
文件结构:
Mapper类位置不变,Mapper.xml位置改变
2、属性优化
编写db.properties配置文件
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username=root
password=123456
在核心配置文件中引入
<!--引用外部配置文件-->
<properties resource="db.properties">
<property name="username" value="root"/>
<property name="password" value="123456"/>
</properties>
引用
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
注意:
-
可以直接引入外部文件
-
可以在其中增加一些属性配置
-
如果两个文件有同一个字段,优先使用外部配置文件的
3、别名优化
-
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置.
-
意在降低冗余的全限定类名书写
可以给实体类起别名
<typeAliases>
<typeAlias type="com.pojo.User" alias="User"/>
</typeAliases>
也可以指定一个包,每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author,;若有注解,则别名为其注解值。见下面的例子:
<typeAliases>
<package name="com.pojo"/>
</typeAliases>
4、接口绑定
接口绑定就是把接口里的方法与对应执行的 SQL 进行绑定,以及 SQL 执行的结果与方法的返回值进行转换匹配。
(1)、注解绑定
//这种方式不用写mapper.xml
@Select("select * from `user` where id = #{id}")
public teacher selectTeacherByID(int id);
(2)、SQL绑定
<select id="selectUserByID" parameterType="int" resultType="test.student">
select id,name,age,stuCountry stu_country from `user` where id = #{id}
</select>
四、映射器
映射器作用:
-
定义参数类型
-
描述缓存
-
描述 SQL 语句
-
定义查询结果和POJO的映射关系
1、映射器分类
(1)、xml映射器
Person p = session.selectOne("com.mybatis.mydemo.mapper.PersonMapper.selectPersonById", 1);
(2)、xml映射器+接口映射器的混合形式
PersonMapper pm = session.getMapper(PersonMapper.class);
// 直接调用接口的方法,查询id为1的Peson数据
Person p2 = pm.selectPersonById(1);
(3)、注解+接口映射器的混合形式
此类形式,将原先xml里面的sql配置信息,变成Java注解的形式写到接口映射器,用法与上面的例子雷同。
2、引入映射器
(1)、通过文件类路径引入XML映射器
<!--每一个Mapper.xml都需要在MyBatis核心配置文件中注册-->
<mappers>
<mapper resource="com/dao/UserMapper.xml"/>
</mappers>
(2)、通过包名引入映射器接口
<mappers>
<package name="com.dao"/>
</mappers>
(3)、用类注册引入映射器接口
<!--每一个Mapper.xml都需要在MyBatis核心配置文件中注册-->
<mappers>
<mapper class="com.dao.UserMapper"/>
</mappers>
-
接口和他的Mapper配置文件必须同名
-
接口和他的Mapper配置文件必须在同一个包下