Spring 整合(连接池+MyBatis)

Spring 整合(连接池+MyBatis)

介绍

整合第三方的工具,一般是基于配置类和工具中的自定义工厂的装配。
而xml文件,现在普遍不推荐

整合第三方案例

整合连接池

连接池放到 ioc容器中管理

xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mybatis="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 整合 druid 数据源连接池,其中将 DruidDataSource 核心类纳入 Spring 容器中管理,并指定相关的初始化方法(init)以及销毁方法(close) -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <!-- 注入相关的连接属性 -->
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://www:3306/lldwb"/>
        <property name="username" value="lldwb"/>
        <property name="password" value="2FANEiC2nAynZtyt"/>
        <!-- 注入连接池相关的配置属性 -->
        <!-- 最大连接池数量 -->
        <property name="maxActive" value="200"/>
        <!-- 预先初始化10个连接到连接池 -->
        <property name="initialSize" value="5"/>
        <!-- 最小空闲连接数(最少保留,其他的空闲抛弃,一般初始化和最小连接是一样的) -->
        <property name="minIdle" value="5"/>
        <!-- 获取连接的最大等待时间,单位:毫秒(比如空闲为0已达到最大,一定时间后还是没有连接就抛异常) -->
        <property name="maxWait" value="2000"/>
        <!-- 连接保持空闲而不被驱逐出连接池的最小时间(只保留最少连接数) -->
        <property name="minEvictableIdleTimeMillis" value="300000"/>
        <!-- 检测连接的间隔时间,单位:毫秒(上线建议关闭) -->
        <property name="timeBetweenEvictionRunsMillis" value="60000"/>
        <!-- 从连接池拿取时检测连接是否有效(高并发时建议关闭) -->
        <property name="testWhileIdle" value="true"/>
        <!-- 放回连接池时检测连接是否有效 -->
        <property name="testOnReturn" value="false"/>
        <!-- 发送一个伪Sql,用于检查连接是否可用(高并发时建议关闭) -->
        <property name="validationQuery" value="select 1"/>
        <!-- 是否缓存 poolPreparedStatements,mysql建议关闭 -->
        <property name="poolPreparedStatements" value="false"/>
    </bean>
</beans>

配置类

一个一个导入

@Configuration
// 读取配置文件
@PropertySource("jdbc.properties")
public class AppConfig {
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    @Value("${pool.maxActive}")
    private Integer maxActive;
    @Value("${pool.initialSize}")
    private Integer initialSize;
    @Value("${pool.minIdle}")
    private Integer minIdle;
    @Value("${pool.maxWait}")
    private Long maxWait;
    @Value("${pool.minEvictableIdleTimeMillis}")
    private Long minEvictableIdleTimeMillis;
    @Value("${pool.timeBetweenEvictionRunsMillis}")
    private Integer timeBetweenEvictionRunsMillis;
    @Value("${pool.testWhileIdle}")
    private Boolean testWhileIdle;
    @Value("${pool.testOnReturn}")
    private Boolean testOnReturn;
    @Value("${pool.validationQuery}")
    private String validationQuery;
    @Value("${pool.poolPreparedStatements}")
    private Boolean poolPreparedStatements;

    @Bean
    public DruidDataSource getDruidDataSource() throws Exception {
        DruidDataSource source = new DruidDataSource();
        source.setUrl(url);
        source.setUsername(username);
        source.setPassword(password);
        source.setMaxActive(maxActive);
        source.setInitialSize(initialSize);
        source.setMinIdle(minIdle);
        source.setMaxWait(maxWait);
        source.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        source.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        source.setTestWhileIdle(testWhileIdle);
        source.setTestOnReturn(testOnReturn);
        source.setValidationQuery(validationQuery);
        source.setPoolPreparedStatements(poolPreparedStatements);
        return source;
    }
}

文件输入流导入

配置文件中的 key 需要和 DruidDataSource 中对应

@Configuration
public class AppConfig {

    @Bean
    public DruidDataSource getDruidDataSource() throws Exception {
        // 创建 Properties
        Properties prop = new Properties();
        // 获取一个输入流来读取 properties 文件
        InputStream input = AppConfig.class.getClassLoader().getResourceAsStream("jdbc.properties");
        // 将输入流加载到 properties 中
        prop.load(input);
        // 通过 DruidDataSourceFactory 来创建
        DruidDataSource source = (DruidDataSource) DruidDataSourceFactory.createDataSource(prop);
        return source;
    }
}

整合mybatis

把 SqlSession 放到 ioc容器 管理,同时也不需要创建自己创建dao接口的实现类,使用扫描dao接口所在的包,这样利用动态代理在运行时创建所有的dao接口的实现类,并自动注册到spring容器中

maven依赖包

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.13</version>
</dependency>
<!-- 添加 mybatis 整合 spring 的依赖 -->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>2.0.6</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.3.30</version>
</dependency>

xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd">

<!-- 整合 druid 数据源连接池,其中将 DruidDataSource 核心类纳入 Spring 容器中管理,并指定相关的初始化方法(init)以及销毁方法(close) -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <!-- 注入相关的连接属性 -->
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://www:3306/lldwb"/>
        <property name="username" value="lldwb"/>
        <property name="password" value="2FANEiC2nAynZtyt"/>
        <!-- 注入连接池相关的配置属性 -->
        <!-- 最大连接池数量 -->
        <property name="maxActive" value="200"/>
        <!-- 预先初始化10个连接到连接池 -->
        <property name="initialSize" value="5"/>
        <!-- 最小空闲连接数(最少保留,其他的空闲抛弃,一般初始化和最小连接是一样的) -->
        <property name="minIdle" value="5"/>
        <!-- 获取连接的最大等待时间,单位:毫秒(比如空闲为0已达到最大,一定时间后还是没有连接就抛异常) -->
        <property name="maxWait" value="2000"/>
        <!-- 连接保持空闲而不被驱逐出连接池的最小时间(只保留最少连接数) -->
        <property name="minEvictableIdleTimeMillis" value="300000"/>
        <!-- 检测连接的间隔时间,单位:毫秒(上线建议关闭) -->
        <property name="timeBetweenEvictionRunsMillis" value="60000"/>
        <!-- 从连接池拿取时检测连接是否有效(高并发时建议关闭) -->
        <property name="testWhileIdle" value="true"/>
        <!-- 放回连接池时检测连接是否有效 -->
        <property name="testOnReturn" value="false"/>
        <!-- 发送一个伪Sql,用于检查连接是否可用(高并发时建议关闭) -->
        <property name="validationQuery" value="select 1"/>
        <!-- 是否缓存 poolPreparedStatements,mysql建议关闭 -->
        <property name="poolPreparedStatements" value="false"/>
    </bean>

    <!-- 装配 SqlSessionFactory,也就是整合 mybatis 到 spring
    关键点在于将 mybatis 的相关配置放在 spring 中设置并管理 SqlSessionFactory -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- SqlSessionFactoryBean 需要注入 dataSource -->
        <property name="dataSource" ref="dataSource"/>
        <!-- 注入其他配置属性值 -->
        <!-- 指定实体类的包,用于创建别名 -->
        <property name="typeAliasesPackage" value="org.example.entity"/>
        <!-- mapper 映射配置文件的路径 -->
        <property name="mapperLocations" value="classpath:mappers/*.xml"/>
    </bean>

    <!-- 配置扫描dao接口所在的包,这样利用动态代理在运行时创建所有的dao接口的实现类,并自动注册到spring容器中 -->
    <mybatis:scan base-package="org.example.dao"/>
</beans>

配置类

@Configuration
// 扫描dao接口的包,动态生成dao接口的代理实现
// 等效于xml中的<mybatis:scan/>
@MapperScan(basePackages = "org.example.dao")
public class AppConfig {

    @Bean
    public SqlSessionFactoryBean getSqlSessionFactoryBean(DruidDataSource dataSource) throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);
        factoryBean.setTypeAliasesPackage("org.example.entity");
        factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mappers/*.xml"));
        return factoryBean;
    }
}

整合分页插件(整合mybatis的基础上)

maven依赖包

<!-- 分页插件-->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.3.2</version>
</dependency>

xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd">

<!-- 整合 druid 数据源连接池,其中将 DruidDataSource 核心类纳入 Spring 容器中管理,并指定相关的初始化方法(init)以及销毁方法(close) -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <!-- 注入相关的连接属性 -->
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://www:3306/lldwb"/>
        <property name="username" value="lldwb"/>
        <property name="password" value="2FANEiC2nAynZtyt"/>
        <!-- 注入连接池相关的配置属性 -->
        <!-- 最大连接池数量 -->
        <property name="maxActive" value="200"/>
        <!-- 预先初始化10个连接到连接池 -->
        <property name="initialSize" value="5"/>
        <!-- 最小空闲连接数(最少保留,其他的空闲抛弃,一般初始化和最小连接是一样的) -->
        <property name="minIdle" value="5"/>
        <!-- 获取连接的最大等待时间,单位:毫秒(比如空闲为0已达到最大,一定时间后还是没有连接就抛异常) -->
        <property name="maxWait" value="2000"/>
        <!-- 连接保持空闲而不被驱逐出连接池的最小时间(只保留最少连接数) -->
        <property name="minEvictableIdleTimeMillis" value="300000"/>
        <!-- 检测连接的间隔时间,单位:毫秒(上线建议关闭) -->
        <property name="timeBetweenEvictionRunsMillis" value="60000"/>
        <!-- 从连接池拿取时检测连接是否有效(高并发时建议关闭) -->
        <property name="testWhileIdle" value="true"/>
        <!-- 放回连接池时检测连接是否有效 -->
        <property name="testOnReturn" value="false"/>
        <!-- 发送一个伪Sql,用于检查连接是否可用(高并发时建议关闭) -->
        <property name="validationQuery" value="select 1"/>
        <!-- 是否缓存 poolPreparedStatements,mysql建议关闭 -->
        <property name="poolPreparedStatements" value="false"/>
    </bean>

    <!-- 装配 SqlSessionFactory,也就是整合 mybatis 到 spring
    关键点在于将 mybatis 的相关配置放在 spring 中设置并管理 SqlSessionFactory -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- SqlSessionFactoryBean 需要注入 dataSource -->
        <property name="dataSource" ref="dataSource"/>
        <!-- 注入其他配置属性值 -->
        <!-- 指定实体类的包,用于创建别名 -->
        <property name="typeAliasesPackage" value="org.example.entity"/>
        <!-- mapper 映射配置文件的路径 -->
        <property name="mapperLocations" value="classpath:mappers/*.xml"/>

        <!-- 设置分页插件 -->
        <property name="plugins">
            <!-- 装配分页拦截器 -->
            <bean class="com.github.pagehelper.PageInterceptor">
                <!-- 给分页拦截器注入相关的属性值 -->
                <property name="properties">
                    <props>
                        <!-- 数据库方言 -->
                        <prop key="helperDialect">mysql</prop>
                        <!-- 启用分页参数注解支持 -->
                        <prop key="supportMethodsArguments">true</prop>
                        <!-- 分页合理化 -->
                        <prop key="reasonable">true</prop>
                    </props>
                </property>
            </bean>
        </property>
    </bean>

    <!-- 配置扫描dao接口所在的包,这样利用动态代理在运行时创建所有的dao接口的实现类,并自动注册到spring容器中 -->
    <mybatis:scan base-package="org.example.dao"/>
</beans>

配置类

SqlSessionFactoryBean 中装配分页插件
// 最后将分页拦截器设置到SqlSessionFactoryBean的插件中
factoryBean.setPlugins(pageInterceptor);
装配分页拦截器
@Bean
public PageInterceptor getPageInterceptor(){
    // 创建分页拦截器
    PageInterceptor pageInterceptor = new PageInterceptor();
    // 创建 Properties,Properties 类表示一组持久的属性
    Properties properties = new Properties();
    properties.setProperty("helperDialect","mysql");
    properties.setProperty("supportMethodsArguments","true");
    properties.setProperty("reasonable","true");
    // 将分页属性设置到拦截器中
    pageInterceptor.setProperties(properties);
    // 分页拦截器返回给 SqlSessionFactoryBean
    return pageInterceptor;
}
配置

dao方法需要有@Param("pageNum") Integer pageNum, @Param("pageSize") Integer pageSize形参的存在

整合事务

Maven依赖

spring的事务框架,支持编程式事务也支持声明式事务,声明式事务基于AOP来实现

 <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-tx</artifactId>
     <version>5.3.30</version>
 </dependency>

配置类

// 启用事务注解驱动,这样就可以在业务类中使用 @Transaction 注解
@EnableTransactionManagement
public class AppConfig {
    /**
     * 装配事务管理器,并注入数据源
     * 这样事务管理器就可以基于AOP来管理Connection的事务操作
     * @param dataSource
     * @return
     */
    @Bean
    public PlatformTransactionManager txManager(DataSource dataSource){
        return new DataSourceTransactionManager(dataSource);
    }
}

注解

@Transaction:当 @Transactional 注解放到类上时,表示这个类中的所有方法都享有事务功能(同理方法上同样如此)
rollbackFor 属性:表示当遇到什么异常将进行事务的回滚,默认是遇到任意的运行时异常将自动回滚事务
propagation 属性:表示事务传播级别,不同的事务传播级别,支持的事务范围将不一样,默认:Propagation.REQUIRED
注意:在这种情况下事务传播级别会