什么是 MyBatis?
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
Mybatis 官方文档 : http://www.mybatis.org/mybatis-3/zh/index.html
GitHub : https://github.com/mybatis/mybatis-3
持久化
持久化是将程序数据在持久状态和瞬时状态转换的机制。
- 即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的对象存储在数据库中,或者存储在磁盘文件中、XML数据文件中等等。
- JDBC就是一种持久化机制。文件IO也是一种持久化机制。
- 在生活中 : 将鲜肉冷藏,吃的时候再解冻的方法也是。将水果做成罐头的方法也是。
为什么需要持久化服务?那是由于内存本身的缺陷引起的
- 内存断电后数据会丢失,但有一些对象是无论如何都不能丢失的,比如银行账号等,遗憾的是,人们还无法保证内存永不掉电。
- 内存过于昂贵,与硬盘、光盘等外存相比,内存的价格要高2~3个数量级,而且维持成本也高,至少需要一直供电吧。所以即使对象不需要永久保存,也会因为内存的容量限制不能一直呆在内存中,需要持久化来缓存到外存。
持久层
什么是持久层?
- 完成持久化工作的代码块 . —-> dao层 【DAO (Data Access Object) 数据访问对象】
- 大多数情况下特别是企业级应用,数据持久化往往也就意味着将内存中的数据保存到磁盘上加以固化,而持久化的实现过程则大多通过各种关系数据库来完成。
- 不过这里有一个字需要特别强调,也就是所谓的“层”。对于应用系统而言,数据持久功能大多是必不可少的组成部分。也就是说,我们的系统中,已经天然的具备了“持久层”概念?也许是,但也许实际情况并非如此。之所以要独立出一个“持久层”的概念,而不是“持久模块”,“持久单元”,也就意味着,我们的系统架构中,应该有一个相对独立的逻辑层面,专著于数据持久化逻辑的实现.
- 与系统其他部分相对而言,这个层面应该具有一个较为清晰和严格的逻辑边界。 【说白了就是用来操作数据库存在的!】
为什么需要 Mybatis
- Mybatis就是帮助程序猿将数据存入数据库中 , 和从数据库中取数据 .
- 传统的jdbc操作 , 有很多重复代码块 .比如 : 数据取出时的封装 , 数据库的建立连接等等… , 通过框架可以减少重复代码,提高开发效率 。
- MyBatis 是一个半自动化的ORM框架 (Object Relationship Mapping) –>对象关系映射
- 所有的事情,不用Mybatis依旧可以做到,只是用了它,所有实现会更加简单!技术没有高低之分,只有使用这个技术的人有高低之别
- MyBatis的优点
- 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件就可以了,易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
- 灵活:mybatis 不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过 sql 语句可以满足操作数据库的所有需求。
- 解除 sql 与程序代码的耦合:通过提供 DAO 层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql 和代码的分离,提高了可维护性。
- 提供 xml 标签,支持编写动态sql。
Mybatis 入门
数据库环境
----新建数据库
CREATE DATABASE `mybatis`;
USE `mybatis`;
----新建表
DROP TABLE if EXISTS `user`;
CREATE TABLE `user`(
`id` INT(20) NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`name` VARCHAR(30) DEFAULT NULL COMMENT '姓名',
`pwd` VARCHAR(30) DEFAULT NULL COMMENT '密码',
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT charset=utf8;
---插入数据
INSERT into `user` (`name`,`pwd`) VALUES
('hresh','123456'),
('hresh2','123456'),
('hresh3','123456')
基本环境搭建
1、pom.xml
dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
</dependencies>
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.jdbc.Driver"/>
<!--jdbc.url=jdbc:mysql://localhost:3306/oto?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC-->
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&useSSL=true&serverTimezone=UTC&characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="1234567"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/msdn/mapper/UserMapper.xml"/>
</mappers>
</configuration>
3、工具类:MybatisUtil.java
public class MybatisUtil {
private static SqlSessionFactory sqlSessionFactory;
static {
String resource = "mybatis-config.xml";
try {
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。 接着再从 SqlSessionFactory 实例中获得 SqlSession 的实例。SqlSession 提供了在数据库执行 SQL 命令所需的所有方法 。
4、实体类:User.java
@Data
@AllArgsConstructor
public class User {
private int id;
private String name;
private String pwd;
}
5、接口类:UserMapper.java
public interface UserMapper {
List<User> getUserList();
User selectUser(int id);
User getUser(Map<String,Object> map);
List<User> getUserLike(String name);
List<User> getUserLike2(String name);
int updateUser(User user);
int insertUser(User user);
int deleteUser(User user);
}
6、编写 UserMapper.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.msdn.mapper.UserMapper">
<select id="getUserList" resultType="com.msdn.bean.User">
select * from mybatis.user
</select>
<select id="selectUser" parameterType="int" resultType="com.msdn.bean.User">
select * from mybatis.user where id = #{id}
</select>
<select id="getUser" parameterType="map" resultType="com.msdn.bean.User">
select * from mybatis.user where name = #{name}
</select>
<!--select * from mybatis.user where name like "%"#{name}"%"-->
<select id="getUserLike" parameterType="String" resultType="com.msdn.bean.User">
select * from mybatis.user where name like #{name}
</select>
<select id="getUserLike2" parameterType="String" resultType="com.msdn.bean.User">
select * from mybatis.user where name like "%"#{name}"%"
</select>
<insert id="insertUser" parameterType="com.msdn.bean.User">
insert into mybatis.user(name,pwd) values(#{name},#{pwd})
</insert>
<update id="updateUser" parameterType="com.msdn.bean.User">
update mybatis.user set name = #{name} where id=#{id};
</update>
<delete id="deleteUser" parameterType="com.msdn.bean.User">
delete from mybatis.user where id=#{id}
</delete>
</mapper>
7、测试类
public class UserTest {
@Test
public void getUser(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
//方式一
//方法一有很多优势,首先它不依赖于字符串字面值,会更安全一点
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users = userMapper.getUserList();
//方式二
// List<User> users = sqlSession.selectList("com.msdn.mapper.UserMapper.getUserList");
for (User user :
users) {
System.out.println(user);
}
sqlSession.close();
}
@Test
public void getUser2(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
Map<String, Object> map = new HashMap<String, Object>();
map.put("name","hresh");
map.put("id","2");
User user = userMapper.getUser(map);
System.out.println(user);
sqlSession.close();
}
@Test
public void getUserLike(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
String name = "%hresh%";
// List<User> users = userMapper.getUserLike(name);
List<User> users = userMapper.getUserLike2("resh");
for (User u :
users) {
System.out.println(u);
}
sqlSession.close();
}
@Test
public void selectOne(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.selectUser(2);
System.out.println(user);
sqlSession.close();
}
@Test
public void insertOne(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = new User(11,"acorn","23455");
int res = userMapper.insertUser(user);
sqlSession.commit();
sqlSession.close();
}
@Test
public void updateOne(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = new User(3,"she","123453");
userMapper.updateUser(user);
sqlSession.commit();
sqlSession.close();
}
@Test
public void deleteOne(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = new User(3,"she","123453");
userMapper.deleteUser(user);
sqlSession.commit();
sqlSession.close();
}
}
Mybatis 执行流程
作用域理解
- SqlSessionFactoryBuilder 的作用在于创建 SqlSessionFactory,创建成功后,SqlSessionFactoryBuilder 就失去了作用,所以它只能存在于创建 SqlSessionFactory 的方法中,而不要让其长期存在。因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。
- SqlSessionFactory 可以被认为是一个数据库连接池,它的作用是创建 SqlSession 接口对象。因为 MyBatis 的本质就是 Java 对数据库的操作,所以 SqlSessionFactory 的生命周期存在于整个 MyBatis 的应用之中,所以一旦创建了 SqlSessionFactory,就要长期保存它,直至不再使用 MyBatis 应用,所以可以认为 SqlSessionFactory 的生命周期就等同于 MyBatis 的应用周期。
- 由于 SqlSessionFactory 是一个对数据库的连接池,所以它占据着数据库的连接资源。如果创建多个 SqlSessionFactory,那么就存在多个数据库连接池,这样不利于对数据库资源的控制,也会导致数据库连接资源被消耗光,出现系统宕机等情况,所以尽量避免发生这样的情况。
- 因此在一般的应用中我们往往希望 SqlSessionFactory 作为一个单例,让它在应用中被共享。所以说 SqlSessionFactory 的最佳作用域是应用作用域。
- 如果说 SqlSessionFactory 相当于数据库连接池,那么 SqlSession 就相当于一个数据库连接(Connection 对象),你可以在一个事务里面执行多条 SQL,然后通过它的 commit、rollback 等方法,提交或者回滚事务。所以它应该存活在一个业务请求中,处理完整个请求后,应该关闭这条连接,让它归还给 SqlSessionFactory,否则数据库资源就很快被耗费精光,系统就会瘫痪,所以用 try…catch…finally… 语句来保证其正确关闭。
- 所以 SqlSession 的最佳的作用域是请求或方法作用域。
注意事项
Maven静态资源过滤问题
在 pom.xml 文件中新增如下配置:
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
IDEA 连接 Mysql 数据库
Mysql 依赖根据版本不同配置略有不同
Mysql 5.x
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&useSSL=true&serverTimezone=UTC&characterEncoding=utf-8
username=root
password=123456
Mysql 8.x
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&useSSL=true&serverTimezone=UTC&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username=root
password=123456
需要更换 driver 对象,同时需要在 url 中指定时区。