Springboot 2.x + Mybatis 基本实现以及多数据源实现

it2022-05-05  266

1. 基本环境搭建

博客中有非常多的文章讲springboot 2.x + mybatis 搭建环境,这里就不展开了一步一步细讲了,只对关键的需要注意的点进行描述展示。

1. 1 依赖引入

通过Maven新建一个基本的springboot项目,在其依赖中加入一下关键包,具体版本号参考注释,要注意版本大更新引起的依赖变化。有一点要注意,下面的依赖组成只是形成一个能支持mybatis的小项目,要支持其他如web功能,在根据需要添加其他依赖。

<dependencies> <!-- version: 2.1.0 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <!-- 5.1.46 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- 1.1.18 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> </dependency> <!-- 2.0.4 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>

1.2 构建 mybatis 的基本目录结构

源码包下基本包:domain、mapper;资源目录下的mybatis/sqlmap目录(放置xxxMapper.xml文件)。mybatis-config.xml是mybatis的配置文件,可选,因为基本的配置在application.yml中就可以配置。 然后在启动类中打开mybatis的扫描开关,扫描目录对于上面的mapper包结构

@SpringBootApplication @MapperScan(basePackages = {"com.leon.mybatis.mapper"}) // 这里可以指定多个,看看源码,这个basepackages属性是个数组 public class MybatisApplication { public static void main(String[] args) { SpringApplication.run(MybatisApplication.class, args); } }

1.3 基本配置

经过上面两步的收拾,在配置一下数据库连接就可以测试类,基本配置如下:

mybatis: configuration: map-underscore-to-camel-case: true # 配置数据库和属性的驼峰映射 mapper-locations: classpath:mybatis/sqlmap/*/*.xml # xxxMapper.xml的目录,也可以配置多个目录,逗号分隔 spring: datasource: url: jdbc:mysql://127.0.0.1:3307/mybatis username: root password: root type: com.alibaba.druid.pool.DruidDataSource # 使用druid数据源,上面依赖引入类alibaba的DruidDataSource连接池 driver-class-name: com.mysql.jdbc.Driver logging: level: com.leon.mybatis.mapper=TRACE # 开启对于mapper下的sql输出

1.4 最后

最后就是没有了,上面3步就搞定了,写个简单查询测试下就行,在详细的参考这个连接?Spring boot Mybatis 整合(完整版)

2. DruidDataSource连接池下的多数据源实现

有时面向 *** 固定 *** 多数据源的需求时,代码也得支持多数据源,所幸在springboot和mybatis组合下,这一点也不难,咱们还是快速实现一个小工程,中间穿插需要注意的要点,拒绝啰嗦。

2.1 依赖引入

还是快速搭建一个普通的springboot项目,然后依赖结构如下:

<!-- version: 2.1.0 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <!-- 1.1.18 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> </dependency> <!-- 5.1.46 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!-- 2.0.4 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>

2.2 构建包结构

包结构大致组成和上面一样,区别只是分了不同的业务方向(也就是不同的数据库映射),如图: 在上图中的domain包、mapper包和资源目录mybatis/sqlmap下都根据不同数据源分成了primary和secondary,这个要注意一下,下面配置多个数据源会用得到。另外在config包中,会放置每个数据源的初始化Config。

2.3 属性配置

# 双数据源配置 datasource: primary: url: jdbc:mysql://127.0.0.1:3307/primary username: root password: root driverClassName: com.mysql.jdbc.Driver secondary: url: jdbc:mysql://127.0.0.1:3307/secondary username: root password: root driverClassName: com.mysql.jdbc.Driver

datasource.primary和datasource.secondary是自定义的,关键是后面的子属性,这些都是构建数据库连接池所必须,其他性能属性,参考 附录1

2.4 分别声明初始化数据源

多个数据源下,在spring的上下文中会生成多个Datasource的对象,这本来是各单例的对象,现在存在多个,就要声明其中一个是主,那我们首先看这个主数据源的config代码

@Configuration @MapperScan(basePackages = {"com.leon.multimybatis.mapper.primary"}, sqlSessionFactoryRef = "primarySqlSessionFactory") public class PrimaryDatasourceConfiguration { @Primary @Bean(name="primaryDataSource") @ConfigurationProperties(prefix = "datasource.primary") public DataSource primaryDataSource() { return new DruidDataSource(); } @Primary @Bean(name = "primarySqlSessionFactory") public SqlSessionFactory primarySqlSessionFactory(@Qualifier("primaryDataSource")DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); // mybatis配置采用了xml文件形式,通过这种方式放入到mybatis上下文中 bean.setConfigLocation(new PathMatchingResourcePatternResolver() .getResource("classpath:mybatis/mybatis-config.xml")); // 指定要扫描的mapper.xml文件路径,注意不同数据的xml文件路径要区分开 Resource[] mapInfo = new PathMatchingResourcePatternResolver() .getResources("classpath:mybatis/sqlmap/primary/*.xml"); bean.setMapperLocations(mapInfo); return bean.getObject(); } }

这个configuration中,需要注意的有一下几点:

在类上添加@MapperScan注解,在basePackages属性中配置这个数据源需要管理的Mapper,注意路径。同时在属性sqlSessionFactoryRef中配置下面方法中的SqlSessionFactory实例的名称类中的第一个方法,声明DruidDataSource数据源,并指定这个Bean的名称,要和其他数据区分开,同时添加Primary注解,即声明成主Datasource。注意@ConfigurationProperties注解,里面的prefix值就是资源文件中对于数据库连接信息的前缀类中第二个方法,声明主SqlSessionFactory,在其参数中用@Qualifier注解指定要注入哪个DataSource(多数据源会有多个),其他看一下注释把。

在把第二个的数据源的声明代码贴上,基本一样,只是不再是主数据源,没有了@Primary注释,其他就是对应路径的配置需要注意。

@Configuration @MapperScan(basePackages = {"com.leon.multimybatis.mapper.secondary"}, sqlSessionFactoryRef = "secondarySqlSessionFactory") public class SecondaryDatasourceConfiguration { @Bean(name="secondaryDataSource") @ConfigurationProperties(prefix="datasource.secondary") public DataSource secondaryDataSource() { return new DruidDataSource(); } @Bean(name = "secondarySqlSessionFactory") public SqlSessionFactory secondarySqlSessionFactory(@Qualifier("secondaryDataSource")DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); bean.setConfigLocation(new PathMatchingResourcePatternResolver().getResource("classpath:mybatis/mybatis-config.xml")); Resource[] mapInfo = new PathMatchingResourcePatternResolver().getResources("classpath:mybatis/sqlmap/secondary/*.xml"); bean.setMapperLocations(mapInfo); return bean.getObject(); } }

2.5 测试一下

用单元测试搞一下,测试代码如下:

@RunWith(SpringRunner.class) @SpringBootTest public class MultiMybatisApplicationTests { // UserInfoMapper 位于 com.leon.multimybatis.mapper.secondary 包下 @Autowired private UserInfoMapper userInfoMapper; // SpamEmailMapper 位于 com.leon.multimybatis.mapper.primary 包下 @Autowired private SpamEmailMapper spamEmailMapper; @Test public void testMultiDB(){ List<UserInfo> userList = userInfoMapper.findAll(); List<SpamEmailReport> emailList = spamEmailMapper.findByCondition(null, -1, 0, 0, 10); userList.forEach(user -> System.out.println(user.getSubscribedArray())); System.out.println("------------------------"); emailList.forEach(email -> System.out.println(email.getSpamEmailAddress())); } }

UserInfoMapper和SpamEmailMapper分别位于两个数据源mapperScan的目录下,也就是分别用来不同的数据源,输出结果部分如下

com.alibaba.druid.pool.DruidDataSource : {dataSource-1} inited com.alibaba.druid.pool.DruidDataSource : {dataSource-2} inited ['default'] ['default'] ['default'] ['default'] ['default'] ['default'] ['default'] ['default'] ['default'] ------------------------ whsntml@xYD.cnjww.com 111@cxcx.com 222@coco.com 444@coco.com bbb@zom.com 333@cxcx.com 111@coco.com s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@71075444: startup date [Thu Jul 18 17:05:00 CST 2019]; root of context hierarchy com.alibaba.druid.pool.DruidDataSource : {dataSource-1} closing ... com.alibaba.druid.pool.DruidDataSource : {dataSource-1} closed com.alibaba.druid.pool.DruidDataSource : {dataSource-2} closing ... com.alibaba.druid.pool.DruidDataSource : {dataSource-2} closed

控制台输出可以看出,分别有两个数据启动了。

如果要在加几个数据源,就是在配置中添加对于的连接信息,在新增初始化类就可以。

3. 动态数据源切换

上面一个单数据源,一个双数据源,都是在数据固定的情况下,如果数据源不固定,或者读写分离,上面的写法就太啰嗦和冗余了,硬编码的缺点就很明显了,下面我们试试通过代码实现按需切换数据源。

动态数据源比较复杂,大家还是参考一下两个博主的内容吧: Spring Boot + Mybatis多数据源和动态数据源配置 SpringBoot + Mybatis + Druid多数据源集成的心得

附录1

com.alibaba.druid.pool.DruidDataSource 基本配置参数如下:

配置缺省值说明name配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。 如果没有配置,将会生成一个名字,格式是:“DataSource-” + System.identityHashCode(this)jdbcUrl连接数据库的url,不同数据库不一样。例如: mysql : jdbc:mysql://10.20.153.104:3306/druid2 oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnautousername连接数据库的用户名password连接数据库的密码。如果你不希望密码直接写在配置文件中,可以使用ConfigFilter。详细看这里:https://github.com/alibaba/druid/wiki/使用ConfigFilterdriverClassName根据url自动识别 这一项可配可不配,如果不配置druid会根据url自动识别dbType,然后选择相应的driverClassName(建议配置)initialSize0初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时maxActive8最大连接池数量maxIdle8已经不再使用,配置了也没效果minIdle最小连接池数量maxWait获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。poolPreparedStatementsfalse是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。maxOpenPreparedStatements-1要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100validationQuery用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用。testOnBorrowtrue申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。testOnReturnfalse归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能testWhileIdlefalse建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。timeBetweenEvictionRunsMillis有两个含义: 1) Destroy线程会检测连接的间隔时间;2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明numTestsPerEvictionRun不再使用,一个DruidDataSource只支持一个EvictionRunminEvictableIdleTimeMillisconnectionInitSqls物理连接初始化的时候执行的sqlexceptionSorter根据dbType自动识别当数据库抛出一些不可恢复的异常时,抛弃连接filters属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有: 监控统计用的filter:stat日志用的filter:log4j防御sql注入的filter:wallproxyFilters类型是List<com.alibaba.druid.filter.Filter>,如果同时配置了filters和proxyFilters,是组合关系,并非替换关系

参考文章: 数据源 DruidDataSource的应用和监控


最新回复(0)