MyBatis-01-初识MyBatis
一、简介
1.1 什么是MyBatis
- 简介
- MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。
- MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
- MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
- 特点
- 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
- 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
- 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
- 提供映射标签,支持对象与数据库的orm字段关系映射
- 提供对象关系映射标签,支持对象关系组建维护
- 提供xml标签,支持编写动态sql
- 官方文档
- Github
1.2 持久化与持久层
1. 持久化
- 什么是持久化?
- 持久化是将程序数据在持久状态和瞬时状态间转换的机制。
- 简单来说就是把内存中的数据保存在外存上
- 持久化是将程序数据在持久状态和瞬时状态间转换的机制。
- 为什么要持久化?
- 内存的断点即失特性决定了内存无法长久存储数据
- 虽然我们可以保证某台服务器7*24运行,但是万一意外发生的话,没有持久化的数据就会全部丢失
2. 持久层
-
什么是持久层?
-
专门负责持久化操作的逻辑层,由该层统一对数据库层进行操作
-
1.3 为什么要用MyBatis
-
用的人多啊,用的人多说明肯定优秀啊,不优秀的话为什么用的人多呢
-
简化了传统的JDBC操作,提高了开发效率
-
所有的事情,不用Mybatis依旧可以做到,只是用了它,所有实现会更加简单!
技术没有高低之分,只有使用这个技术的人有高低之别
二、Hello MyBatis
2.1 搭建测试环境
-
建立测试数据库
DROP TABLE IF EXISTS user; CREATE TABLE `user` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar(20) DEFAULT (NULL), `pwd` varchar(20) DEFAULT ('123456'), PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; INSERT INTO `mybatis`.`user`(`name`, `pwd`) VALUES ('李四', '12345'),('张三','1234'),('bruce','root');
-
在maven中导入MySQL和MyBatis依赖
<!--MySQL驱动--> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.22</version> </dependency> <!--MyBatis--> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.6</version> </dependency>
-
创建核心配置文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis? useSSL=true&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> </configuration>
2.2 准备工作
-
创建MyBatis工具类
- 用于构建 SqlSessionFactory,MyBatis中的SqlSession提供了在数据库执行 SQL 命令所需的所有方法。我们可以通过 SqlSession 实例来直接执行已映射的 SQL 语句
package com.pbx.utils; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; /** * @author BruceXu * @date 2020/10/30 */ public class MyBatisUtils { private static SqlSessionFactory sqlSessionFactory; static { try { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } public static SqlSession getSqlSession() { return sqlSessionFactory.openSession(); } }
-
创建实体类
package com.pbx.pojo; /** * @author BruceXu * @date 2020/10/30 */ public class User { private int id; private String name; private String pwd; public User() { } public User(int id, String name, String pwd) { this.id = id; this.name = name; this.pwd = pwd; } 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 String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", pwd='" + pwd + '\'' + '}'; } }
-
编写Mapper接口
package com.pbx.mapper; import com.pbx.pojo.User; import java.util.List; /** * @author BruceXu * @since 2020/10/30 */ public interface UserMapper { List<User> getUsers(); }
2.3 编写代码
-
编写Mapper.xml配置文件
- namespace要和mapper接口文件的包名保持一致
- id要对应上mapper接口中提供的函数名
- resultType代表SQL语句的返回值
- parameterType表示对应方法中需要接收的参数类型
- 如果出现需要传递参数,可以使用
#{}
表示占位符。而且可以无视实体类中的权限修饰符,可以直接取出其中的属性
<?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.pbx.mapper.UserMapper"> <select id="getUsers" resultType="com.pbx.pojo.User"> select * from mybatis.user </select> </mapper>
-
在mybatis-config.xml中注册UserMapper
<mappers> <mapper resource="com/pbx/mapper/Mapper.xml" /> </mappers>
2.4 测试
-
编写测试类
package com.pbx.mapper; import com.pbx.pojo.User; import com.pbx.utils.MyBatisUtils; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; /** * @author BruceXu * @date 2020/10/30 */ public class TestUserMapper { @Test public void test() { SqlSession sqlSession = MyBatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> list = mapper.getUsers(); for (User user : list) { System.out.println(user); } } }
-
测试运行
-
运行出现如下错误
-
错误原因如下:Error parsing SQL Mapper Configuration. Cause: java.io.IOException: Could not find resource com/pbx/mapper/Mapper.xml,找不导我们的Mapper.xml文件。但是观察项目结构后发现,诶,Mapper.xml文件明明就有啊,为什么会找不到呢?
- 这个问题产生的原因是由于maven静态资源的导出存在问题,我们需要调整静态资源的过滤条件,能让maven过滤到他
-
解决方法:修改maven的静态资源过滤
<build> <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> </build>
-
修改之后,就可以到正确的输出结果了
-
2.5 在Maven中使用MyBatis的一般步骤
- 导入相应的数据库驱动和MyBatis依赖
- 编写mybatis-config.xml主要配置文件
- 构建SqlSessionFactory
- 创建实体类
- 创建mapper接口,编写mapper.xml实现SQL操作
- 在mybatis-config.xml中配置注册使用到的mapper.xml文件
- 进行使用
- 注意
- 每个线程都应该有它自己的 SqlSession 实例。
- SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
- 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。
- 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。
- 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。
- 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它
- 不仅仅是在web应用中,每当一个SqlSession用完之后,一定要关闭它