一、什么是持久层框架
什么是持久层
持久是相对于瞬时来说的,持久层可以理解成数据保存在数据库或者硬盘一类可以长久存储的设备里面,不像放在内存中那样断电就消失了,也就是把数据存在持久化设备上。
数据是非常重要的资产,远比应用程序本身更重要,所以需要把数据持久化。持久化可以通过很多方式,写文件和数据库都可以。现在企业一般都会选择把数据持久化到数据库中,因为还需要对存储的数据进行查询统计分析,数据库的数据最终还是会写到磁盘上的。
什么是框架
在编程领域,软件框架是指一种抽象形式,它提供了一个具有通用功能的软件,这些功能可以由使用者编写代码来有选择的进行更改,从而提供服务于特定应用的软件。软件框架提供了一种标准的方式来构建并部署应用。
软件框架是一种通用的、可复用的软件环境,它提供特定的功能,作为一个更大的软件平台的一部分,用以促进软件应用、产品和解决方案的开发工作。软件框架可能会包含支撑程序、编译器、代码、库、工具集以及 API,它把所有这些部件汇集在一起,以支持项目或系统的开发。
形象点比喻(但不够严谨),框架就是条生产线,这条生产线上有很多工人(代码)在工作。生产线的管理者(程序员)负责管理这条生产线,比如说有的工序是空的,那么你就可以安排自己的工人进去,让他去达成你的目标。有些工序上的工人干的工作和你预期的不同,你也可以安排自己的工人把他替换掉。
总之,框架可以看作某个领域的整体解决方案
二、什么是MyBatis
JDBC的缺点
前面说到需要将数据保存在数据库中,最开始是使用JDBC来进行操作数据库进行增删改查等操作,使用JDBC流程如下
JDBC操作数据库有两个很大的缺点
- 流程复杂,开发效率低存在大量重复代码
- SQL语句硬编码在程序中,耦合度高
如何解决呢?
引出MyBatis
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
- MyBatis将重要的步骤抽取出来可以人工定制,其他步骤自动化;
- 重要步骤都是写在配置文件中(好维护);
- 完全解决数据库的优化问题;
- MyBatis底层就是对原生JDBC的一个简单封装;
- 既将java编码与sql抽取了出来,还不会失去自动化功能;半自动的持久化层框架;
- Mybatis是一个轻量级的框架;
三、MyBatis Hello World
环境搭建
创建一个Maven项目mybatis-hello-world,导入maven依赖
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.16</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.18</version> <scope>provided</scope> </dependency> 复制代码
在数据库中创建一个t_employee表,并插入一条数据
SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for t_employee -- ---------------------------- DROP TABLE IF EXISTS `t_employee`; CREATE TABLE `t_employee` ( `id` int(11) NOT NULL AUTO_INCREMENT, `empname` varchar(255) NOT NULL, `gender` int(1) DEFAULT NULL, `email` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of t_employee -- ---------------------------- BEGIN; INSERT INTO `t_employee` VALUES (1, 'stark', 0, 'stark@stark-industry.com'); COMMIT; SET FOREIGN_KEY_CHECKS = 1; 复制代码
使用MyBatis操作数据库
在entity包中创建Java Bean命名为Employee,用来封装表中的数据
@Data public class Employee { private Integer id; private String empName; private String email; private Integer gender; } 复制代码
在dao包中创建EmployeeDao接口,增加getEmpById方法,根据ID查询Employee
public interface EmployeeDao { Employee getEmpById(Integer id); } 复制代码
导入MyBatis相关依赖
<dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.7</version> </dependency> 复制代码
在resource目录下增加mybatis全局配置文件mybatis-config.xml,它可以指定MyBatis连接的数据库以及注册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> <settings> <!--驼峰命名转换 --> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings> <!--设置默认指向的数据库--> <environments default="dev"> <!--配置环境,不同的环境不同的id名字--> <environment id="dev"> <!-- 采用JDBC方式对数据库事务进行commit/rollback --> <transactionManager type="JDBC"></transactionManager> <!--采用连接池方式管理数据库连接--> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> </configuration> 复制代码
在resource目录下新建mappers文件夹,新增employee.xml SQL映射文件
<?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.citi.dao.EmployeeDao"> <select id="getEmpById" resultType="com.citi.entity.Employee"> select * from t_employee where id = #{id} </select> </mapper> 复制代码
- select:用来定义一个查询操作
- id:方法名,相当于这个配置是对于某个方法的实现
- resultType:指定方法运行后的返回值类型,查询操作必须指定
- #{属性名}:代表取出传递过来的某个参数的值
在全局配置文件mybatis-config.xml中注册SQL映射文件
<mappers> <mapper resource="mappers/employee.xml"/> </mappers> 复制代码
- resource表示从类路径下查找资源
配置logback.xml,用于打印SQL执行详情
<?xml version="1.0" encoding="UTF-8"?> <configuration> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>[%thread] %d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <!-- 日志输出级别(优先级高到低): error: 错误 - 系统的故障日志 warn: 警告 - 存在风险或使用不当的日志 info: 一般性消息 debug: 程序内部用于调试信息 trace: 程序运行的跟踪信息 --> <root level="debug"> <appender-ref ref="console"/> </root> </configuration> 复制代码
测试EmployeeDao
生成EmployeeDao的测试类,测试getEmpById()方法。
- 根据全局配置文件先创建一个SqlSesssionFactor
- sqlSessionFactory中获取sqlSession对象操作数据库即可
public class EmployeeDaoTest { @Test public void getEmpById() throws Exception{ //1、根据全局配置文件创建出一个SqlSessionFactory //SqlSessionFactory:是SqlSession工厂,负责创建SqlSession对象; //SqlSession:sql会话(代表和数据库的一次会话); String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //4、调用之前的方法; Employee employee; SqlSession openSession = sqlSessionFactory.openSession(); try { //2、获取和数据库的一次会话;getConnection(); //3、使用SqlSession操作数据库,获取到dao接口的实现 EmployeeDao employeeDao = openSession.getMapper(EmployeeDao.class); employee = employeeDao.getEmpById(1); } finally{ openSession.close(); } System.out.println(employee); } } 复制代码
执行测试
在EmployeeDao接口中在增加3个方法
int updateEmployee(Employee employee); boolean deleteEmployee(Integer id); int insertEmployee(Employee employee); 复制代码
在employee.xml中增加相应的SQL
<!--增删改不用写返回值类型,增删改返回的是影响了多少行,MyBatis自动判断 如果是boolean,影响0行自动封装为false,否则为true, 参数类型也不用写 #{属性名}--> <update id="updateEmployee" parameterType="com.citi.entity.Employee"> UPDATE t_employee SET empname = #{empName}, gender = #{gender}, email = #{email} WHERE id = #{id} </update> <delete id="deleteEmployee"> DELETE FROM t_employee WHERE id = #{id} </delete> <insert id="insertEmployee" useGeneratedKeys="true" parameterType="com.citi.entity.Employee"> INSERT INTO t_employee(empname,gender,email) values (#{empName},#{gender},#{email}) </insert> 复制代码
修改EmployeeDaoTest,新增测试方法
public class EmployeeDaoTest { SqlSessionFactory sqlSessionFactory = null; SqlSession openSession = null; @Before public void setUp() throws Exception { //1、根据全局配置文件创建出一个SqlSessionFactory //SqlSessionFactory:是SqlSession工厂,负责创建SqlSession对象; //SqlSession:sql会话(代表和数据库的一次会话); String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); openSession = sqlSessionFactory.openSession(); } @Test public void getEmpById() throws Exception{ EmployeeDao employeeDao = openSession.getMapper(EmployeeDao.class); Employee employee = employeeDao.getEmpById(1); System.out.println(employee); } @Test public void updateEmployee() { EmployeeDao employeeDao = openSession.getMapper(EmployeeDao.class); Employee updateEmployee = new Employee(); updateEmployee.setId(1); updateEmployee.setEmpName("Tony Stark"); updateEmployee.setEmail("stark@stark-industry.com"); updateEmployee.setGender(0); employeeDao.updateEmployee(updateEmployee); Employee employee = employeeDao.getEmpById(1); System.out.println(employee); } @Test public void deleteEmployee() { EmployeeDao employeeDao = openSession.getMapper(EmployeeDao.class); System.out.println(employeeDao.getEmpById(6)); boolean isDelete = employeeDao.deleteEmployee(6); System.out.println(isDelete); } @Test public void insertEmployee() { Employee employee = new Employee(); employee.setEmpName("peter"); employee.setGender(0); employee.setEmail("peter@gmail.com"); EmployeeDao employeeDao = openSession.getMapper(EmployeeDao.class); employeeDao.insertEmployee(employee); System.out.println(employeeDao.getEmpById(2)); } @After public void tearDown() throws Exception { openSession.close(); } } 复制代码
执行所有的测试方法。