Mybatis
持久层的概念
就是将业务数据存储到磁盘,具备长期存储能力,只要磁盘不损坏,在断电或者其他情况下,重新开启系统仍然可以读取这些数据。
Mybatis的特点
1.不屏蔽SQL,能够更加精确地定位SQL语句,可以对其进行优化和改造。
2.提供强大、灵活的映射机制。
3.在Mybatis中,提供了使用Mapper的接口编程,只要一个接口和一个XML就能创建映射器,进一步简化我们的工作。
下面会通过介绍来展示Mybatis的特点
搭建环境
导入maven依赖或者去官网下载jar包
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
了解Mybatis的核心组件
SQLSessionFactoryBuilder(构造器)
它会根据配置或者代码来生成SqlSessionFactory,采用的是分布构建的Builder模式。
SqlSessionFactory(工厂接口)
依靠它来生成SqlSession,使用的是工厂模式。
SqlSession(会话)
一个既可以发送SQL执行返回结果,也可以获取Mapper的接口。在现有的技术中,一般我们会让其在业务逻辑代码中“消失”,而使用的是Mybatis提供的SQL Mapper接口编程技术,它可以提高代码的可读性和可维护性。
SQL Mapper(映射器)
Mybatis新设计存在的组件,它由一个Java接口和XML文件(或注解)构成,需要给出对应的SQL和映射规则。它负责发送SQL去执行,并返回结果。
逐一介绍这些组件:
SqlSessionFactory(工厂接口)
使用Mybatis首先是使用配置或者代码去生产SqlSessionFactory,而Mybatis提供了构造器SqlSessionFactoryBuilder.采用的是Builder模式。在Mybatis中,既可以通过读取配置的XML文件的形式去生成SqlSessionFactory,也可以通过Java代码的形式去生成SqlSessionFactory。建议使用XML
使用XML构建SqlSessionFactory
首先,在Mybatis中的XML分为两类,一类是基础配置文件,通常只有一个,主要是配置一些最基本的上下文参数和运行环境;另外一类是映射文件,他可以配置映射关系、SQL、参数等信息。
基础配置文件,命名为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>
<!--别名-->
<typeAliases>
<typeAlias type="com.spring.domain.Role" alias="role"/>
</typeAliases>
<!--数据库环境-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value="pzh200061"/>
<property name="url" value="jdbc:mysql://localhost:3306/ssm?useSSL=false"/>
</dataSource>
</environment>
</environments>
<!--映射文件-->
<mappers>
<mapper resource="com/spring/mapper/RoleMapper.xml"></mapper>
</mappers>
</configuration>
描述基础配置文件:
元素定义了一个别名role,它代表着com.spring.domain.Role这个类。这样定义后,在Mybatis上下文中就可以使用别名去代替全限定名了。
元素的定义,这里描述的是数据库。它里面的 元素是配置食物管理器,这里采用的是MyBatis的JDBC管理器方式。然后采用去配置数据源,其中属性type="POOLED"代表采用MyBatis内部提供的连接池方式,最后定义一些关于JDBC的属性信息。
元素代表引入的那些映射器。
通过上面的基础配置文件,就可以用代码生成SqlSessionFactory了
public class MybatisConfig {
SqlSessionFactory sqlSessionFactory = null;
String resource = "mybatis-config.xml";
InputStream inputStream;
public void config(){
try {
inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}catch (Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
MybatisConfig config = new MybatisConfig();
}
}
首先读取mybatis-config.xml,然后通过SqlSessionFactoryBuilder的Builder方法去创建SqlSessionFactory.
SqlSession
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zzzt5HFp-1608705504433)(C:\Users\pzh\AppData\Roaming\Typora\typora-user-images\image-20201203135820665.png)]
在Mybatis中,SqlSession是其核心接口。在MyBatis中有两个实现类,DefaultSqlSession和SqlSessionManager.DefaultSqlSession是单线程使用的,而SqlSessionManager是多线程环境下使用的。SqlSession的作用类似于一个JDBC中的Connection对象,代表着一个连接资源的启用。它的作用有三个:
获取Mapper接口
发送SQL给数据库
控制数据库事务
SqlSession的创建
public class MybatisConfig {
SqlSessionFactory sqlSessionFactory = null;
String resource = "mybatis-config.xml";
InputStream inputStream;
SqlSession sqlSession = null;
public void config(){
try {
inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}catch (Exception e){
e.printStackTrace();
}
}
public void createSqlSession(){
//打开SqlSession会话
sqlSession = sqlSessionFactory.openSession();
try {
sqlSession.commit();//提交事务
}catch (Exception e){
e.printStackTrace();
sqlSession.rollback();//回滚事务
}finally {
//关闭资源
if(sqlSession != null){
sqlSession.close();
}
}
}
public static void main(String[] args) {
MybatisConfig config = new MybatisConfig();
config.config();
config.createSqlSession();
}
}
映射器
映射器时MyBatis中最重要、最复杂的组件,它由一个接口和对应的XML文件(或注解)组成。它可以配置一下内容:
描述映射规则
提供SQL语句,并可以配置SQL参数类型、返回类型、缓存刷新等信息。
配置缓存。
提供动态SQL。
基于XML文件的形式
首先新建一个POJO
public class Role {
private Long id;
private String roleName;
private String note;
public Role(){
}
public Role(Long id, String roleName, String note) {
this.id = id;
this.roleName = roleName;
this.note = note;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
@Override
public String toString() {
return "Role{" +
"id=" + id +
", roleName='" + roleName + '\'' +
", note='" + note + '\'' +
'}';
}
}
映射器的主要作用就是将SQL查询到的结果映射为一个POJO,或者将POJO的数据插入到数据库中,并定义一些关于缓存等的重要内容。
新建一个roles表
首先定义一个接口:
public interface RoleMapper {
public Role getRole(Long id);
}
之前定义的mybatis-config.xml文件中配置了这样一段代码:
<!--映射文件-->
<mappers>
<mapper resource="com/spring/mapper/role/RoleMapper.xml"/>
</mappers>
它的作用就是引入一个XML文件。用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.spring.mapper.role.RoleMapper">
<select id="getRole" parameterType="long" resultType="role">
select id,roleName,note from roles where id = #{id}
</select>
</mapper>
这样就完成了一个映射器的定义。
元素中的属性namespace所对应的是一个接口的全限定名,于是Mybatis上下文就可以通过它找到对应的接口。
元素表明这是一条查询语句,而属性id标识了这条SQL,属性parameterType="long"说明传递给SQL的是一个long型的参数,而resultYtpe="role"表示返回的是一个role类型的返回值。而role是之前配置文件mybatis-config.xml配置的别名。
这条SQL中的#{id}表示传递进去的参数。
注解实现映射器
public interface RoleMapper2 {
@Select("select id,roleName,note from roles where id = #{id}")
public Role getRole(Long id);
}
SQLSession发送SQL
有了映射器之后就能够通过SqlSession发送SQL了。我们以getRole这条SQL为例看看如何发送SQL。
package com.spring.config;
import com.spring.domain.Role;
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.InputStream;
public class MybatisConfig {
SqlSessionFactory sqlSessionFactory = null;
String resource = "mybatis-config.xml";
InputStream inputStream;
SqlSession sqlSession = null;
public void config(){
try {
inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}catch (Exception e){
e.printStackTrace();
}
}
public void createSqlSession(){
//打开SqlSession会话
sqlSession = sqlSessionFactory.openSession();
try {
sqlSession.commit();//提交事务
}catch (Exception e){
e.printStackTrace();
sqlSession.rollback();//回滚事务
}
}
public void roleTest(){
Role role = sqlSession.selectOne("com.spring.mapper.RoleMapper.getRole",1L);
System.out.println(role);
if(sqlSession!=null){
sqlSession.close();
}
}
public static void main(String[] args) {
MybatisConfig config = new MybatisConfig();
config.config();
config.createSqlSession();
config.roleTest();
}
}
执行结果:Role{id=1, roleName='小明', note='弟弟'}
用Mapper接口发送SQL
public void mapperTest(){
RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
System.out.println(roleMapper.getRole(1L));
if(sqlSession!=null){
sqlSession.close();
}
}
通过SqlSession的getMapper方法来获取一个Mapper接口,就可以调用它的方法了。因为XML文件或者接口注解定义的SQL都可以通过“类的全限定名+方法名"查找,所以MyBatis会启用对应的SQL进行运行,并返回结果。
增删改查实现
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.spring.mapper.RoleMapper">
<select id="getRole" parameterType="long" resultType="role">
select id,roleName,note from roles where id = #{id}
</select>
<insert id="insertRole" parameterType="role">
insert into roles(roleName,note) values (#{roleName},#{note})
</insert>
<delete id="deleteRole" parameterType="long">
delete from roles where id = #{id}
</delete>
<update id="updateRole" parameterType="role">
update roles set roleName = #{roleName},note = #{note}
where id = #{id}
</update>
<select id="findRoles" parameterType="string" resultType="role">
select id,roleName,note
from roles
where roleName like concat('%',#{roleName},'%')
</select>
</mapper>
接口定义:
package com.spring.mapper;
import com.spring.domain.Role;
import java.util.List;
public interface RoleMapper {
public Role getRole(Long id);
public int deleteRole(Long id);
public int updateRole(Role role);
public int insertRole(Role role);
public List<Role> findRoles(String roleName);
}
插入
package com.spring.config;
import com.spring.domain.Role;
import com.spring.mapper.RoleMapper;
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.InputStream;
public class MybatisConfig {
private static volatile SqlSessionFactory sqlSessionFactory = null;
final static String resource = "mybatis-config.xml";
static InputStream inputStream;
SqlSession sqlSession = null;
public static SqlSessionFactory getSqlSessionFactory(){
if(sqlSessionFactory==null){
synchronized (MybatisConfig.class){
if(sqlSessionFactory==null){
try {
inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}catch (Exception e){
e.printStackTrace();
}
}
}
}
return sqlSessionFactory;
}
public void insertRole(Role role){
//打开SqlSession会话
sqlSession = sqlSessionFactory.openSession();
try {
RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
System.out.println(roleMapper.insertRole(role));
sqlSession.commit();//提交事务
}catch (Exception e){
e.printStackTrace();
sqlSession.rollback();//回滚事务
}finally {
if(sqlSession!=null){
sqlSession.close();
}
}
}
public static void main(String[] args) {
MybatisConfig.getSqlSessionFactory();
MybatisConfig config = new MybatisConfig();
Role role = new Role("小李","叔叔");
config.insertRole(role);
}
}
删除:
public void deleteRole(long id){
//打开SqlSession会话
sqlSession = sqlSessionFactory.openSession();
try {
RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
System.out.println(roleMapper.deleteRole(id));
sqlSession.commit();//提交事务
}catch (Exception e){
e.printStackTrace();
sqlSession.rollback();//回滚事务
}finally {
if(sqlSession!=null){
sqlSession.close();
}
}
}
修改
public void updateRole(Role role){
//打开SqlSession会话
sqlSession = sqlSessionFactory.openSession();
try {
RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
System.out.println(roleMapper.updateRole(role));
sqlSession.commit();//提交事务
}catch (Exception e){
e.printStackTrace();
sqlSession.rollback();//回滚事务
}finally {
if(sqlSession!=null){
sqlSession.close();
}
}
}
查询
public void findRoles(String roleName){
//打开SqlSession会话
sqlSession = sqlSessionFactory.openSession();
try {
RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
List<Role> roles = roleMapper.findRoles(roleName);
for(Role role : roles){
System.out.println(role);
}
sqlSession.commit();//提交事务
}catch (Exception e){
e.printStackTrace();
sqlSession.rollback();//回滚事务
}finally {
if(sqlSession!=null){
sqlSession.close();
}
}
}
Mybatis配置
<?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="datasource.properties"/>
<!--别名-->
<typeAliases>
<typeAlias type="com.spring.domain.Role" alias="role"/>
</typeAliases>
<!--数据库环境-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value="pzh200061"/>
<property name="url" value="jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=CTT"/>
</dataSource>
</environment>
</environments>
<!--映射文件-->
<mappers>
<mapper resource="mapper/RoleMapper.xml"/>
</mappers>
</configuration>
Mybatis映射
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value="pzh200061"/>
<property name="url" value="jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=CTT"/>
</dataSource>
</environment>
</environments>
<!--映射文件-->
<mappers>
<mapper resource="mapper/RoleMapper.xml"/>
</mappers>