Spring整合Mybatis
# Spring整合Mybatis⛵️
# 1 、添加依赖MyBatis-Spring
<!--mybatis-spring-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.2</version>
</dependency>
2
3
4
5
6
MyBatis-Spring
会帮助你将 MyBatis
代码无缝地整合到 Spring
中。它将允许 MyBatis
参与到 Spring
的事务管理之中,创建映射器 mapper
和 SqlSession
并注入到 bean
中,以及将 Mybatis
的异常转换为 Spring
的 DataAccessException
。最终,可以做到应用代码不依赖于 MyBatis
,Spring
或 MyBatis-Spring
。
所以我们此时需要一个mybatis-spring
的2.0
版本的jar的坐标
# 2、定义SqlSessionFactory
首先需要创建一个spring的applicationContext.xml配置文件,以下所有的配置都在applicationContext.xml文件中完成。
要想和 Spring
和 MyBatis
一起使用,需要在 Spring
应用上下文中定义至少两样东西:一个 SqlSessionFactory
和至少一个数据映射器类。
在 MyBatis-Spring 中,可使用 SqlSessionFactoryBean
来创建 SqlSessionFactory
。 要配置这个工厂 bean,只需要把下面代码放在 Spring 的 applicationContext的配置文件中:
<!--1、MyBaits-Spring配置sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--需要一个唯一的必要属性DataSource数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
2
3
4
5
# 3、创建dataSource
数据源
注意:SqlSessionFactory
需要一个 dataSource
(数据源)。 这可以是任意的 dataSource
,只需要和配置其它 Spring
数据库连接一样配置它就可以了。
在Spring
的applicationContext
的配置文件中配置数据源,这里使用的是alibaba
的Druid(德鲁伊)
:
<!--配置dataSource数据源,配置数据库连接-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="driverClassName" value="${driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
2
3
4
5
6
7
8
以上需要用到database.properties
在src/main/resources
目录下新建一个database.properties
配置文件,用于编写连接MySQL
数据库的相关信息,database.properties
的内容如下:
driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/goku?useSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=795200
2
3
4
在dataSource
的bean
如果想引用database.properties
中的内容,需要进行文件关联,关联的方法如下:
<!--关联外部db.properties,注意使用context节点-->
<comtext:property-placeholder location="classpath:database.properties"/>
2
# 4、配置数据库连接池
在配置数据源的同时,也需要配置数据库连接池。
- 原生的JDBC访问思路,每次请求建立一个数据库链接,使用完成后,释放数据库链接。建立数据库连接耗时耗费资源,一个数据库服务器能够同时建立的连接数也是有限的,在大型的Web应用中,可能同时会有成百上千的访问数据库的请求,如果Web应用程序为每一个客户请求分配一个数据库连接,将导致性能的急剧下降。
- 数据库连接池的意义在于,能够重复利用数据库连接(池化技术),提高对请求的响应时间和服务器的性能。连接池的实现思路是,预先建立了多个数据库连接对象,然后将连接对象保存到连接池中,当客户请求到来时,直接从池中取出一个连接对象为客户服务,当请求完成之后,客户程序调用close()方法,将连接对象放回池中。
- 常见的数据库连接池技术:
DBCP(DataBase connection pool)数据库连接池
、C3P0
、druid
等。
这里配置数据库连接池,我们采用阿里巴巴的druid(德鲁伊)
,德鲁伊为阿里巴巴的数据源,(数据库连接池),集合了c3p0
、dbcp
、proxool
等连接池的优点,还加入了日志监控,有效的监控DB
池连接和SQL
的执行情况。
# druid的优点
高性能。性能比dbcp、c3p0高很多。只要是jdbc支持的数据库,druid都支持,对数据库的支持性好。并且Druid针对oracle、mysql做了特别优化。提供监控功能。可以监控sql语句的执行时间、ResultSet持有时间、返回行数、更新行数、错误次数、错误堆栈等信息,来了解连接池、sql语句的工作情况,方便统计、分析SQL的执行性能。
# druid的参数和配置详解
配置 | 缺省值 | 说明 |
---|---|---|
name | 配置这个属性的意义在于,如果存在多个数据源,监控的时候 可以通过名字来区分开来。如果没有配置,将会生成一个名字, 格式是:"DataSource-" + System.identityHashCode(this) | |
jdbcUrl | 连接数据库的url,不同数据库不一样 | |
username | 连接数据库的用户名 | |
password | 连接数据库的密码。如果你不希望密码直接写在配置文件中,可以使用ConfigFilter | |
driverClassName | 根据url自动识别 这一项可配可不配,如果不配置druid会根据url自动识别dbType,然后选择相应的driverClassName | |
initialSize | 0 | 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时 |
maxActive | 8 | 最大连接池数量 |
maxIdle | 8 | 已经不再使用,配置了也没效果 |
minIdle | 最小连接池数量 | |
maxWait | 获取连接时最大等待时间,单位毫秒。配置了maxWait之后, 缺省启用公平锁,并发效率会有所下降, 如果需要可以通过配置useUnfairLock属性为true使用非公平锁。 | |
poolPreparedStatements | false 是否缓存preparedStatement,也就是PSCache。 | |
PSCache | 对支持游标的数据库性能提升巨大,比如说oracle。 在mysql5.5以下的版本中没有PSCache功能,建议关闭掉。 | |
maxOpenPreparedStatements | -1 | 要启用PSCache,必须配置大于0,当大于0时,在Druid中,不会存在Oracle下PSCache占用内存过多的问题, 可以把这个数值配置大一些,比如说100 |
validationQuery | 用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、 testWhileIdle都不会其作用。 | |
testOnBorrow | true | 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 |
testOnReturn | false | 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能 |
testWhileIdle | false | 建议配置为true,不影响性能,并且保证安全性。 申请连接的时候检测,如果空闲时间大于 timeBetweenEvictionRunsMillis, 执行validationQuery检测连接是否有效。 |
timeBetweenEvictionRunsMillis | 有两个含义: 1) Destroy线程会检测连接的间隔时间 2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明 | |
numTestsPerEvictionRun | 不再使用,一个DruidDataSource只支持一个EvictionRun minEvictableIdleTimeMillis | |
connectionInitSqls | 物理连接初始化的时候执行的sql | |
exceptionSorter | 根据dbType自动识别 | 当数据库抛出一些不可恢复的异常时,抛弃连接 |
filters | 属性类型是字符串,通过别名的方式配置扩展插件, filters 属性类型是字符串,通过别名的方式配置扩展插件, | |
proxyFilters | 类型是List<com.alibaba.druid.filter.Filter>, 如果同时配置了filters和proxyFilters, 是组合关系,并非替换关系 |
# druid配置操作步骤
# 1、配置依赖
<!--druid数据库连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.26</version>
</dependency>
2
3
4
5
6
# 2、配置Spring的applicationContext.xml配置文件
<!--2.2 配置数据库连接配置-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="driverClassName" value="${driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!--3、druid数据库池的配置-->
<property name="filters" value="${filters}"/>
<!-- 最大并发连接数 -->
<property name="maxActive" value="${maxActive}"/>
<!-- 初始化连接数量 -->
<property name="initialSize" value="${initialSize}"/>
<!-- 配置获取连接等待超时的时间 -->
<property name="maxWait" value="${maxWait}"/>
<!-- 最小空闲连接数 -->
<property name="minIdle" value="${minIdle}"/>
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis"
value="${timeBetweenEvictionRunsMillis}"/>
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis"
value="${minEvictableIdleTimeMillis}"/>
<property name="validationQuery" value="${validationQuery}"/>
<property name="testWhileIdle" value="${testWhileIdle}"/>
<property name="testOnBorrow" value="${testOnBorrow}"/>
<property name="testOnReturn" value="${testOnReturn}"/>
<property name="maxOpenPreparedStatements"
value="${maxOpenPreparedStatements}"/>
<!-- 打开 removeAbandoned 功能 -->
<property name="removeAbandoned" value="${removeAbandoned}"/>
<!-- 1800 秒,也就是 30 分钟 -->
<property name="removeAbandonedTimeout"
value="${removeAbandonedTimeout}"/>
<!-- 关闭 abanded 连接时输出错误日志 -->
<property name="logAbandoned" value="${logAbandoned}"/>
</bean>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# 3、applicationContext.xml中拦截器配置
<bean id="druid-stat-interceptor"
class="com.alibaba.druid.support.spring.stat.DruidStatInterceptor">
</bean>
<bean id="druid-stat-pointcut"
class="org.springframework.aop.support.JdkRegexpMethodPointcut"
scope="prototype">
<property name="patterns">
<list>
<value>com.etc.util.mg.mapper.*</value>
<value>com.maven.dao.*</value>
</list>
</property>
</bean>
<aop:config>
<aop:advisor advice-ref="druid-stat-interceptor" pointcut-ref="druid-stat-pointcut"/>
</aop:config>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 4、修改database.properties
driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/goku?useSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=795200
filters=stat,wall
maxActive=20
initialSize=1
maxWait=60000
minIdle=10
maxIdle=15
timeBetweenEvictionRunsMillis=60000
minEvictableIdleTimeMillis=300000
validationQuery=SELECT 'x'
testWhileIdle=true
testOnBorrow=false
testOnReturn=false
maxOpenPreparedStatements=20
removeAbandoned=true
removeAbandonedTimeout=1800
logAbandoned=true
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
5、配置web.xml配置
<!--连接池 启用 Web 监控统计功能 -->
<filter>
<filter-name>DruidWebStatFilter</filter-name>
<filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class>
<init-param>
<param-name>exclusions</param-name>
<param-value>*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*</param-value>
</init-param>
<init-param>
<param-name>profileEnable</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>DruidWebStatFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>DruidStatView</servlet-name>
<servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
<init-param>
<!-- 用户名 -->
<param-name>loginUsername</param-name>
<param-value>root</param-value>
</init-param>
<init-param>
<!-- 密码 -->
<param-name>loginPassword</param-name>
<param-value>root</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>DruidStatView</servlet-name>
<url-pattern>/druid/*</url-pattern>
</servlet-mapping>
<!-- 连接池 启用 Web 监控统计功能 -->
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 5、启动Tomcat进行访问
启动tomcat,并通过浏览器地址栏输入地址访问
http://localhost:8080/projectname/druid/index.html
# 5、创建发现注册器:MapperScannerConfigurer
Mybatis的MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring
Mybatis在与Spring集成的时候可以配置MapperFactoryBean来生成Mapper接口的代理. 例如:
<bean id="articleMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.singerw.dao.ArticleMapper"/>
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.singerw.dao.UserMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
2
3
4
5
6
7
8
MapperFactoryBean 创建的代理类实现了 UserMapper 接口,并且注入到应用程序中。 因为代理创建在运行时环境中(Runtime,译者注) ,那么指定的映射器必须是一个接口,而 不是一个具体的实现类。
上面的配置有一个很大的缺点,就是系统有很多的配置文件时 全部需要手动编写,所以上述的方式已经很用了。
没有必要在 Spring 的 XML 配置文件中注册所有的映射器。相反,你可以使用一个 MapperScannerConfigurer , 它 将 会 查 找 类 路 径 下 的 映 射 器 并 自 动 将 它 们 创 建 成 MapperFactoryBean。
💛MapperScannerConfigurer 的作用是取代手动添加 Mapper ,自动扫描完成接口代理💛
要创建 MapperScannerConfigurer,可以在 Spring 的配置中添加如下代码:
<!--发现注册器:配置dao接口扫描包,动态的实现了dao接口可以注入到spring容器中!-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 注入 basePackage ,mapper所在的包-->
<property name="basePackage" value="com.singerw.dao"/>
<!-- 注入sqlSessionFactoryBean,注意是beanName不是ref 而是value -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
2
3
4
5
6
7
这里需要注意一点,要将<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
中value="sqlSessionFactory
的sqlSessionFactory
这个值,是我们在第三步定义的SqlSessionFactory
时bean
的ID。
<!--1、MyBaits-Spring配置sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--需要一个唯一的必要属性DataSource数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
2
3
4
5
# 5、单元测试
到此为止,我们就可以使用Mapper来进行数据访问:
数据库表,entity,Mapper文件,以及在Mapper中使用注解实现crud,目前没有用到Mapper.xml文件.
<!-- 为了方便进行单元测试,添加spring-test包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.1.RELEASE</version>
</dependency>
2
3
4
5
6
jupiter5 jar包
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.6.1</version>
<scope>test</scope>
</dependency>
2
3
4
5
6
Junit5的写法:
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
@SpringJUnitConfig(locations = "classpath:applicationContext.xml")
public class BlogTest {
@Autowired
private BlogMapper blogMapper;
@Test
public void testSelectBlog() {
System.out.println(blogMapper.selectBlog(2));
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
# 7、配置log4j日志
# 1、导入jar文件
<!--log4j-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
2
3
4
5
6
# 2、在mybatis-config.xml中配置
新建一个MyBatis的mybatis-config.xml配置文件,在mybatis-config.xml中配置setting,需要中settings标签在配置文件中的位置顺序,mybatis配置文件有这严格的顺序。
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
2
3
# 3、配置log4j的配置文件
新建log4j.properties文件,在文件中插入如下配置:
log4j.rootLogger=DEBUG, console, file
log4j.logger.com.singerw.dao=TRACE
#console
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [%p][%c{1}] - %m%n
log4j.appender.console.Encoding=UTF-8
#file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./logs/log.log
log4j.appender.file.MaxFileSize=500KB
log4j.appender.file.MaxBackupIndex=1
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [%p]-%c{1} - %m%n
log4j.appender.file.encoding=UTF-8
#jibie
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 4、log4j的使用
在applicationContext.xml中关联log4j.properties
外部文件,方法如下:
<!--关联log4j-->
<comtext:property-placeholder location="classpath:log4j.properties"/>
2
- 在要使用Log4j的类中,导入
import org.apache.log4j.Logger;
- 创建日志对象,参数为当前类的
class
在要输出日志的类中加入相关语句来定义属性:
static Logger logger = Logger.getLogger(UserMapperTest.class);
public class UserMapperTest {
static Logger logger = Logger.getLogger(UserMapperTest.class);
@Test
public void testLog4j() {
logger.info("info:进入了testLog4j方法");
logger.debug("debug:进入了进入了testLog4j方法");
logger.error("debug:进入了进入了testLog4j方法");
}
}
2
3
4
5
6
7
8
9
10
# 8、加载mybatis-config.xml配置文件
如果存在一个mybatis-config.xml
的mybatis
全局配置文件,则可以使用applicationContext.xml
中的sqlSessionFactoryBean
来管理并加载:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--需要一个唯一的必要属性DataSource数据源-->
<property name="dataSource" ref="dataSource"/>
<!--绑定mybatis-config.xml的配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!-- 指定读取*.mapper.xml的映射文件位置 -->
<property name="mapperLocations" value="classpath:com/singerw/mapping/*.xml"/>
</bean>
2
3
4
5
6
7
8
9
<property name="mapperLocations" value="classpath:com/singerw/mapping/*.xml"/>
是采用Mybatis中的mapper.xml进行开发时候,需要加入这一句,如果仅仅是注解开发,则不需要再读取mapper.xml映射文件。