数据库框架整合
学习了Spring之后,我们已经了解如何将一个类作为Bean交由IoC容器管理,这样,我们就可以通过更方便的方式来使用Mybatis框架,我们可以直接把SqlSessionFactory、Mapper交给Spring进行管理,并且可以通过注入的方式快速地使用它们。
因此,我们要学习一下如何将Mybatis与Spring进行整合,那么首先,我们需要在之前知识的基础上继续深化学习。
了解数据源
在之前,我们如果需要创建一个JDBC的连接,那么必须使用DriverManager.getConnection()
来创建连接,连接建立后,我们才可以进行数据库操作。而学习了Mybatis之后,我们就不用再去使用DriverManager
为我们提供连接对象,而是直接使用Mybatis为我们提供的SqlSessionFactory
工具类来获取对应的SqlSession
通过会话对象去操作数据库。
那么,它到底是如何封装JDBC的呢?我们可以试着来猜想一下,会不会是Mybatis每次都是帮助我们调用DriverManager
来实现的数据库连接创建?我们可以看看Mybatis的源码:
1 2 3
| public SqlSession openSession(boolean autoCommit) { return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, autoCommit); }
|
在通过SqlSessionFactory
调用openSession
方法之后,它调用了内部的一个私有的方法openSessionFromDataSource
,我们接着来看,这个方法里面定义了什么内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null;
DefaultSqlSession var8; try { Environment environment = this.configuration.getEnvironment(); TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment); tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); Executor executor = this.configuration.newExecutor(tx, execType); var8 = new DefaultSqlSession(this.configuration, executor, autoCommit); } catch (Exception var12) { this.closeTransaction(tx); throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12); } finally { ErrorContext.instance().reset(); }
return var8; }
|
也就是说,我们的数据源配置信息,存放在了Transaction
对象中,那么现在我们只需要知道执行器到底是如何执行SQL语句的,我们就知道到底如何创建Connection
对象了,这时就需要获取数据库的链接信息了,那么我们来看看,这个DataSource
到底是个什么:
1 2 3 4 5 6 7
| public interface DataSource extends CommonDataSource, Wrapper {
Connection getConnection() throws SQLException;
Connection getConnection(String username, String password) throws SQLException; }
|
我们发现,它是在javax.sql
定义的一个接口,它包括了两个方法,都是用于获取连接的。因此,现在我们可以断定,并不是通过之前DriverManager
的方法去获取连接了,而是使用DataSource
的实现类来获取的,因此,也就正式引入到我们这一节的话题了:
数据库链接的建立和关闭是极其耗费系统资源的操作,通过DriverManager获取的数据库连接,一个数据库连接对象均对应一个物理数据库连接,每次操作都打开一个物理连接,使用完后立即关闭连接,频繁的打开、关闭连接会持续消耗网络资源,造成整个系统性能的低下。
因此,JDBC为我们定义了一个数据源的标准,也就是DataSource
接口,告诉数据源数据库的连接信息,并将所有的连接全部交给数据源进行集中管理,当需要一个Connection
对象时,可以向数据源申请,数据源会根据内部机制,合理地分配连接对象给我们。
一般比较常用的DataSource
实现,都是采用池化技术,就是在一开始就创建好N个连接,这样之后使用就无需再次进行连接,而是直接使用现成的Connection
对象进行数据库操作。

当然,也可以使用传统的即用即连的方式获取Connection
对象,Mybatis为我们提供了几个默认的数据源实现,我们之前一直在使用的是官方的默认配置,也就是池化数据源:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?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="${驱动类(含包名)}"/> <property name="url" value="${数据库连接URL}"/> <property name="username" value="${用户名}"/> <property name="password" value="${密码}"/> </dataSource> </environment> </environments> </configuration>
|
这里的type
属性一共三个选项:
- UNPOOLED 不使用连接池的数据源
- POOLED 使用连接池的数据源
- JNDI 使用JNDI实现的数据源(适用于 Java EE 应用服务器环境,例如 Tomcat、WebLogic 等。)
spring+mybatis
使用配置文件实现
1.注解类里注册SqlSessionFactory的bean
1 2 3 4 5 6 7 8 9 10
| @Configuration @ComponentScan("org.example.entity") public class MainConfiguration { @Bean public SqlSessionTemplate sqlSessionTemplate() throws IOException { SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml")); return new SqlSessionTemplate(factory); } }
|
2.配置文件写数据库源:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?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/study"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <mappers> <mapper class="org.example.mapper.TestMapper"/> </mappers> </configuration>
|
3.随便编写一个测试的Mapper类:
1 2 3 4 5 6
| @Data public class Student { private int sid; private String name; private String sex; }
|
1 2 3 4
| public interface TestMapper { @Select("select * from student where sid = 1") Student getStudent(); }
|
1 2 3 4 5 6
| public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(MainConfiguration.class); SqlSessionTemplate template = context.getBean(SqlSessionTemplate.class); TestMapper testMapper = template.getMapper(TestMapper.class); System.out.println(testMapper.getStudent()); }
|
如果我们希望让Spring直接帮助我们管理所有的Mapper,当需要时,可以直接从容器中获取,我们可以直接在配置类上方添加mapper扫描注解:
1 2 3 4
| @Configuration @ComponentScan("org.example.entity") @MapperScan("org.example.mapper") public class MainConfiguration {
|
这样,Mybatis就会自动扫描对应包下所有的接口,并直接被注册为对应的Mapper作为Bean管理,那么我们现在就可以直接通过容器获取了:
1 2 3 4 5
| public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(MainConfiguration.class); TestMapper mapper = context.getBean(TestMapper.class); System.out.println(mapper.getStudent()); }
|
不使用配置文件来实现
请一定注意,必须存在SqlSessionTemplate
或是SqlSessionFactoryBean
的Bean,否则会无法初始化(毕竟要数据库的链接信息)我们接着来看,如果我们希望直接去除Mybatis的配置文件,完全实现全注解配置,那么改怎么去实现呢?我们可以使用SqlSessionFactoryBean
类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Configuration @ComponentScan("org.example.entity") @MapperScan("org.example.mapper") public class MainConfiguration { @Bean public DataSource dataSource(){ return new PooledDataSource("com.mysql.cj.jdbc.Driver", "jdbc:mysql://localhost:3306/study", "root", "123456"); }
@Bean public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){ SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); return bean; } }
|
首先我们需要创建一个数据源的实现类,因为这是数据库最基本的信息,然后再给到SqlSessionFactoryBean
实例,这样,我们相当于直接在一开始通过IoC容器配置了SqlSessionFactory
,这里只需要传入一个DataSource
的实现即可,我们采用池化数据源。
删除配置文件,重新再来运行,同样可以正常使用Mapper。从这里开始,通过IoC容器,Mybatis已经不再需要使用配置文件了,在我们之后的学习中,基于Spring的开发将不会再出现Mybatis的配置文件。
spring事务

脏读:一个事务执行dml,另一个事务查询到修改后的,原事务回滚,另一个事务再次查询就是没修改前的了。
不可重复读(虚读):一个事务执行dml,另一个事务查询到原数据,原事务提交,另一个事务查询到修改后的数据了,另一个事务两次查询到的数据不一样。
幻读:一个事务执行dml,另一个事务查询到修改前的,原事务提交,另一个事务查询到的还是修改前的,另一个事务提交再次查询变成修改后的了。
串行化:一个事务提交后另一个事务才可执行。