Mybatis(超级详细)
MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
总之,Mybatis对JDBC访问数据库的过程进行了封装,简化了JDBC代码,解决JDBC将结果集封装为Java对象的麻烦。
下图是MyBatis架构图:
(1)mybatis-config.xml是Mybatis的核心配置文件,通过其中的配置可以生成SqlSessionFactory,也就是SqlSession工厂
(2)基于SqlSessionFactory可以生成SqlSession对象
(3)SqlSession是一个既可以发送SQL去执行,并返回结果,类似于JDBC中的Connection对象,也是Mybatis中至关重要的一个对象。
(4)Executor是SqlSession底层的对象,用于执行SQL语句
(5)MapperStatement对象也是SqlSession底层的对象,用于接收输入映射(SQL语句中的参数),以及做输出映射(即将SQL查询的结果映射成相应的结果)
2、为什么要使用MyBatis
思考:在开始之前,思考下如何通过JDBC查询Emp表中的所有记录,并封装到一个List集合中返回。(演示:准备数据、导包、导入JDBC程序)
1、使用传统方式JDBC访问数据库:
(1)使用JDBC访问数据库有大量重复代码(比如注册驱动、获取连接、获取传输器、释放资源等);
(2)JDBC自身没有连接池,会频繁的创建连接和关闭连接,效率低;
(3)SQL是写死在程序中,一旦修改SQL,需要对类重新编译;
(4)对查询SQL执行后返回的ResultSet对象,需要手动处理,有时会特别麻烦;
...
2、使用mybatis框架访问数据库:
(1)Mybatis对JDBC对了封装,可以简化JDBC代码;
(2)Mybatis自身支持连接池(也可以配置其他的连接池),因此可以提高程序的效率;
(3)Mybatis是将SQL配置在mapper文件中,修改SQL只是修改配置文件,类不需要重新编译。
(4)对查询SQL执行后返回的ResultSet对象,Mybatis会帮我们处理,转换成Java对象。
...
总之,JDBC中所有的问题(代码繁琐、有太多重复代码、需要操作太多对象、释放资源、对结果的处理太麻烦等),在Mybatis框架中几乎都得到了解决!!
二、MyBatis快速入门
准备数据,创建库和表
创建test库、emp表,并插入若干条记录
-- 1、创建数据库 test 数据库 create database if not exists test charset utf8; use test ; -- 选择yonghedb数据库 -- 2、删除emp表(如果存在) drop table if exists emp; -- 3、在 test 库中创建 emp 表 create table emp( id int primary key auto_increment, name varchar(50), job varchar(50), salary double ); -- 4、往 emp 表中, 插入若干条记录 insert into emp values(null, '张三', '程序员', 3300); insert into emp values(null, '李四', '程序员', 2800); insert into emp values(null, '王五', '程序员鼓励师', 2700); insert into emp values(null, '王二', '部门总监', 4200); insert into emp values(null, '麻子', '程序员', 3000); insert into emp values(null, '最帅三太子', '程序员', 3500); insert into emp values(null, '苍老师', '程序员', 3700); insert into emp values(null, '波多野结衣', 'CEO', 5000);
创建工程,导入所需jar包、创建测试类
1、创建Maven的java工程
2、导入junit、mysql、mybaits、log4j等开发包。在pom.xml文件中引入相关依赖包即可:
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <!-- mysql驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency> <!-- mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.13</version> </dependency> <!-- 整合log4j --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>2.0.7</version> </dependency> </dependencies>
添加mybatis-config.xml文件
1、在src/main/resources目录下,创建mybatis-config.xml文件(MyBatis的核心配置文件)
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"> <!-- MyBatis的全局配置文件 --> <configuration> <!-- 1.配置环境,可配置多个环境(比如:develop开发、test测试) --> <environments default="develop"> <environment id="develop"> <!-- 1.1.配置事务管理方式:JDBC/MANAGED JDBC:将事务交给JDBC管理(推荐) MANAGED:自己管理事务 --> <transactionManager type="JDBC"></transactionManager> <!-- 1.2.配置数据源,即连接池 JNDI/POOLED/UNPOOLED JNDI:已过时 POOLED:使用连接池(推荐) UNPOOLED:不使用连接池 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf-8"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <!-- 2.导入Mapper配置文件,如果mapper文件有多个,可以通过多个mapper标签导入 --> <mappers> <mapper resource="mybatis/EmpMapper.xml"></mapper> </mappers> </configuration>
environments
标签:该标签内部可以配置多个environment,即多种环境,每种环境可以做不同配置或连接不同数据库。例如,开发、测试、生产环境可能需要不同的配置,连接的数据库可能也不相同,因此我们可以配置三个environment,分别对应上面三种不同的环境。
但是要记住,environment可以配置多个,但是最终要使用的只能是其中一个!
environment
标签:内部可以配置多种配置信息,下面介绍事务管理配置和数据源配置。
transactionManage
标签:事务管理配置,mybatis中有两种事务管理方式,也就是type="[JDBC|MANAGED]。
1)JDBC:这个配置就是直接使用了 JDBC的提交和回滚设置,它依赖于从数据源得到的连接来管理事务范围。推荐使用。
2)MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接。需要自己手动添加并管理。不推荐使用。
添加EmpMapper.xml文件
1、在src/main/resources目录下创建mybatis文件夹,创建EmpMapper.xml文件 (实体类的映射文件)
2、EmpMapper.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值应该保证唯一 在程序中通过[ namespace + id ]定位到要执行哪一条SQL语句 --> <mapper namespace="EmpMapper"> <!-- 通过select、insert、update、delete标签声明要执行的SQL --> <!-- 练习1: 查询emp表中的所有员工信息 resultType指定查询的结果将会封装到什么类型中 即使最终返回的结果是集合(List<Emp>),resultType也只需要指定集合中的泛型即可! --> <select id="findAll" resultType="org.example.pojo.Emp"> select * from emp </select> </mapper>
(1)第1行是xml的文档声明,用于声明xml的版本和编码
(2)第2、3、4行,引入了xml约束文档,当前xml文档将会按照mybatis-3-mapper.dtd文件所要求的规则进行书写。
(3)Mapper标签:根标签,其中namespace(名称空间,也叫命名空间),要求不能重复。在程序中通过【namespace + id 】定位到要执行哪一条SQL语句
(4)select标签:用于指定将来要执行的各种SQL语句。标签上可以声明属性,下面介绍常用的属性:id、resultType、resultMap
- id属性:要求值不能重复。将来在执行SQL时,可以通过【namespace + id】找到指定SQL并执行。
- resultType属性:从这条SQL语句中返回所期望类型的类的完全限定名称(包名+类名)。注意如果是集合情形,那应该是集合可以包含的类型,而不能是集合本身。
简而言之,resultType控制查询SQL执行后返回值的类型或集合中的泛型,例如查询emp表中的单条记录,返回值是一个Emp对象,因此,resultType="com.tedu.pojo.Emp";
如果查询emp表中的多条记录,返回值是一个List,此时resultType的值应该集合中的泛型,因此resultType="com.tedu.pojo.Emp"; - resultMap属性:复杂对象结构(例如多表关联查询等)。 使用 resultType 或 resultMap,但不能同时使用。
添加并编写Emp实体类
注意:在当前实例中,Emp类中的属性和数据库表的字段名称必须一致,否则将会无法将结果集封装到Java对象中。
在src/main/java目录下创建 com.tedu.pojo.Emp类,并编辑Emp类:提供私有属性以及对应的getter方法、setter方法,并重写toString方法
package com.tedu.pojo; public class Emp { private Integer id; private String name; private String job; private Double salary; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getJob() { return job; } public void setJob(String job) { this.job = job; } public Double getSalary() { return salary; } public void setSalary(Double salary) { this.salary = salary; } @Override public String toString() { return "Emp{" + "id=" + id + ", name='" + name + '\'' + ", job='" + job + '\'' + ", salary=" + salary + '}'; } }
实现测试类,并测试
在src/test/java下创建FindAllTest.java文件进行写测试用例。
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 org.example.pojo.Emp; import org.junit.Test; import java.io.IOException; import java.io.InputStream; import java.util.List; public class FindAllTest { // 获取SqlSession public SqlSession getSession() throws IOException { // 1.读取mybatis的核心配置文件(mybatis-config.xml) InputStream in = Resources.getResourceAsStream("mybatis-config.xml"); //2.通过配置信息获取一个SqlSessionFactory工厂对象 SqlSessionFactory fac = new SqlSessionFactoryBuilder().build(in); //3.通过工厂获取一个SqlSession对象 SqlSession session = fac.openSession(); return session; } // 查询所有数据 @Test public void findAll() throws IOException{ SqlSession session = getSession(); //4.通过namespace+id找到要执行的sql语句并执行sql语句 List<Emp> list = session.selectList("EmpMapper.findAll"); //5.输出结果 for(Emp e : list) { System.out.println( e ); } } }
执行findAll方法,输出结果。
MyBatis增删改查