Spring Boot从入门到通晓(五)多数据源设置完成及源码剖析
用 Python 读写 Excel 表格
多数据源设置在项目软件中是比较罕见的开发需求,Spring和Spring Boot中对此都有响应的处理方案可供人人参考。在Spring Boot中,如MyBatis、JdbcTemplate以及Jpa都能够设置多数据源。
本文在前一篇“Spring Boot从入门到通晓(四)衔接MySQL数据库(附源码)”文章中项目源码的基础上,来完成Spring Boot集成MyBatis和运用JdbcTemplate两种体式格局设置多数据源。
Spring Boot集成MyBatis和运用JdbcTemplate设置大众文件
1、设置数据源application.properties文件
假定有两个数据源来设置完成,离别对应的名字是oneDataSource和twoDataSource。
在application.properties文件中设置数据源信息以下:
spring.datasource.one.url=jdbc:mysql://123.57.47.154:3306/springboot1 spring.datasource.one.username=root spring.datasource.one.password=wangyoodb spring.datasource.one.driverClassName=com.mysql.cj.jdbc.Driver spring.datasource.two.url=jdbc:mysql://123.57.47.154:3306/springboot2 spring.datasource.two.username=root spring.datasource.two.password=wangyoodb spring.datasource.two.driverClassName=com.mysql.cj.jdbc.Driver
2、数据源设置java类文件
经由过程上一步操纵,应用关键词one和two对数据源举行辨别,只是简朴增添这些信息是没法被Spring Boot自动加载的,需要增添代码来完成加载DataSource,下面小编手动设置DataSourceConfig,用来供应DataSource Bean。
数据源一:新增定名DataSourceOneConfig的java类文件,详细代码以下:
package com.yoodb.study.demo03.datasource; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import javax.sql.DataSource; @Configuration @MapperScan(basePackages = "com.yoodb.study.demo03.mapper.one", sqlSessionFactoryRef = "oneSqlSessionFactory") public class DataSourceOneConfig { @Bean(name = "oneDataSource") @Primary @ConfigurationProperties(prefix = "spring.datasource.one") public DataSource getDateSourceOne() { return DataSourceBuilder.create().build(); } @Bean(name = "oneSqlSessionFactory") @Primary public SqlSessionFactory oneSqlSessionFactory(@Qualifier("oneDataSource") DataSource datasource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(datasource); bean.setMapperLocations( new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/one/*.xml")); return bean.getObject(); } // @Bean("oneSqlSessionTemplate") @Primary public SqlSessionTemplate onesqlsessiontemplate( @Qualifier("oneSqlSessionFactory") SqlSessionFactory sessionfactory) { return new SqlSessionTemplate(sessionfactory); } }
数据源二:新增定名DataSourceTwoConfig的java类文件,详细代码以下:
package com.yoodb.study.demo03.datasource; import com.zaxxer.hikari.HikariDataSource; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import javax.sql.DataSource; @Configuration @MapperScan(basePackages = "com.yoodb.study.demo03.mapper.two", sqlSessionFactoryRef = "twoSqlSessionFactory") public class DataSourceTwoConfig { @Bean(name = "twoDataSource") @ConfigurationProperties(prefix = "spring.datasource.two") public DataSource getDateSourceTwo(DataSourceProperties properties) { return DataSourceBuilder.create(properties.getClassLoader()) .type(HikariDataSource.class) .driverClassName(properties.determineDriverClassName()) .url(properties.determineUrl()) .username(properties.determineUsername()) .password(properties.determinePassword()) .build(); } @Bean(name = "twoSqlSessionFactory") public SqlSessionFactory twoSqlSessionFactory(@Qualifier("twoDataSource") DataSource datasource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(datasource); bean.setMapperLocations( new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/two/*.xml")); return bean.getObject(); } @Bean("twoSqlSessionTemplate") public SqlSessionTemplate twosqlsessiontemplate( @Qualifier("twoSqlSessionFactory") SqlSessionFactory sessionfactory) { return new SqlSessionTemplate(sessionfactory); } }
在上述代码中运用的注解寄义能够参考之前写过“Spring Boot从入门到通晓(三)经常使用注解寄义及用法剖析总结”的文章(见微信民众号“Java精选”),详细运用注解寄义以下:
@Configuration
用于定义设置类,可替代xml设置文件,被注解的类内部包含有一个或多个被@Bean注解的要领,这些要领将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类举行扫描,并用于构建bean定义,初始化Spring容器。
@MapperScan
指定要扫描mapper类包的途径,设置mybatis的接口寄存位置。
@Bean
用于通知要领发生一个Bean对象,然后这个Bean对象交给Spring治理。
@ConfigurationProperties
是Spring Boot供应的范例平安的属性绑定,以第一个Bean为例,@ConfigurationProperties(prefix = “spring.datasource.one”)示意运用spring.datasource.one前缀的数据库设置去建立一个DataSource。
@Primary
能够理解为默许优先选择,不能够同时设置多个,必需增添此注解用于辨别主数据库(默许数据库)。
@Qualifier
来到达注入某个特指bean的作用,示意查找Spring容器中指定名字的对象。
注重:
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(“***”)) mapper的xml情势文件位置必需要设置,不然项目会报no statement错误信息。
3、实体类文件
新增实体类文件,两个数据源公用一个实体类,详细代码以下:
package com.yoodb.study.demo03.bean; public class BootUser { private String id; private String name; private String detail; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDetail() { return detail; } public void setDetail(String detail) { this.detail = detail; } }
集成Mybatis
1、新增mapper xml文件
数据源一:在src/main/resources/mapper/one(不存在文件加新建)建立BootUserOneMapper.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="com.yoodb.study.demo03.mapper.one.BootUserOneMapper" > <resultMap id="BaseResultMap" type="com.yoodb.study.demo03.bean.BootUser" > <id column="id" property="id" jdbcType="VARCHAR" /> <result column="user_name" property="name" jdbcType="VARCHAR" /> <result column="detail" property="detail" jdbcType="VARCHAR" /> </resultMap> <select id="selectAll" resultMap="BaseResultMap"> select id, user_name, detail from boot_user order by detail asc </select> </mapper>
数据源二:在src/main/resources/mapper/two(不存在文件加新建)建立BootUserTwoMapper.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="com.yoodb.study.demo03.mapper.two.BootUserTwoMapper" > <resultMap id="BaseResultMap" type="com.yoodb.study.demo03.bean.BootUser" > <id column="id" property="id" jdbcType="VARCHAR" /> <result column="user_name" property="name" jdbcType="VARCHAR" /> <result column="detail" property="detail" jdbcType="VARCHAR" /> </resultMap> <select id="selectAll" resultMap="BaseResultMap"> select id, user_name, detail from boot_user order by detail asc </select> </mapper>
2、新增mapper接口类文件
数据源一:mapper接口类文件,详细代码以下:
package com.yoodb.study.demo03.mapper.one; import com.yoodb.study.demo03.bean.BootUser; import java.util.List; public interface BootUserOneMapper { List<BootUser> selectAll(); }
数据源二:mapper接口类文件,详细代码以下:
package com.yoodb.study.demo03.mapper.two; import com.yoodb.study.demo03.bean.BootUser; import java.util.List; public interface BootUserTwoMapper { List<BootUser> selectAll(); }
3、建立service类文件
新增文件名BootUserService类文件,详细代码以下:
package com.yoodb.study.demo03.service; import com.yoodb.study.demo03.bean.BootUser; import com.yoodb.study.demo03.mapper.one.BootUserOneMapper; import com.yoodb.study.demo03.mapper.two.BootUserTwoMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class BootUserService { @Autowired private BootUserOneMapper onemapper; @Autowired private BootUserTwoMapper twomapper; public List<BootUser> getUsers(){ List<BootUser> listone = onemapper.selectAll(); List<BootUser> listtwo = twomapper.selectAll(); listone.addAll(listtwo); return listone; } }
4、建立controller类文件
新增文件名BootUserController类文件,详细代码以下:
package com.yoodb.study.demo03; import java.util.List; import com.yoodb.study.demo03.bean.BootUser; import com.yoodb.study.demo03.service.BootUserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/myt") public class BootUserController { @Autowired private BootUserService service; @RequestMapping("/getUsers") public List<BootUser> getUsers() { List<BootUser> list = service.getUsers(); return list; } }
mapper的接口、xml文件及实体文件、service层、controller层建立完成后,目次如图:
5、项目启动
以上操纵完成后,项目启动过程当中控制台报错,错误信息以下:
### Error querying database. Cause: org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "BOOT_USER" not found; SQL statement: select id, user_name, detail from boot_user order by detail asc [42102-200] ### The error may exist in file [F:projectstudyspringboot-study-demo03targetclassesmapperoneBootUserOneMapper.xml] ### The error may involve com.yoodb.study.demo03.mapper.one.BootUserOneMapper.selectAll ### The error occurred while executing a query ### SQL: select id, user_name, detail from boot_user order by detail asc ### Cause: org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "BOOT_USER" not found; SQL statement:
问题剖析:如今Spring Boot最新版本不会将application.properties文件加载到classes目次下,致使没法读取到application.properties文件信息,从而在项目接见的时刻控制台报上述错误信息。
处理要领:就是在pom.xml文件中增添以下设置信息:
<resources> <resource> <!-- 指定resources插件处置惩罚哪一个目次下的资本文件 --> <directory>src/main/resources</directory> <includes> <include>**/**</include> </includes> </resource> </resources>
上述问题处理完后体系能够一般启动,但是在经由过程浏览器接见时照样会报错。
接见地点:
http://localhost:8080/myt/getUsers
错误信息以下:
### Error querying database. Cause: java.lang.IllegalArgumentException: dataSource or dataSourceClassName or jdbcUrl is required. ### The error may exist in file [F:projectstudyspringboot-study-demo03targetclassesmapperoneBootUserOneMapper.xml] ### The error may involve com.yoodb.study.demo03.mapper.BootUserOneMapper.selectAll ### The error occurred while executing a query ### Cause: java.lang.IllegalArgumentException: dataSource or dataSourceClassName or jdbcUrl is required.] with root cause java.lang.IllegalArgumentException: dataSource or dataSourceClassName or jdbcUrl is required.
问题剖析:
1)在Spring Boot 1.* 版本中设置数据源是spring.datasource.url和spring.datasource.driverClassName;
2)在Spring Boot 2.* 版本中设置数据源是spring.datasource.jdbc-url和spring.datasource.driver-class-name;
3)Spring Boot项目中(本文是基于Spring Boot 2.3.0.M2 版本)由于没法读取到application.properties文件中“driver-class-name”和“jdbc-url”两个参数致使项目报错。
处理要领:
将application.properties文件中spring.datasource..url和spring.datasource..driverClassName离别替代成spring.datasource..jdbc-url和spring.datasource..driver-class-name。
*Spring Boot源码剖析:
1)spring.datasource.*.url替代成spring.datasource.*.jdbcUrl也没有任何问题。
源码org.springframework.boot.jdbc包中DatabaseDriver.class文件反编译后,发明url参数必需以“jdbc”入手下手,详细源码以下:
public static DatabaseDriver fromJdbcUrl(String url) { if (StringUtils.hasLength(url)) { Assert.isTrue(url.startsWith("jdbc"), "URL must start with 'jdbc'"); String urlWithoutPrefix = url.substring("jdbc".length()).toLowerCase(Locale.ENGLISH); DatabaseDriver[] var2 = values(); int var3 = var2.length; for(int var4 = 0; var4 < var3; ++var4) { DatabaseDriver driver = var2[var4]; Iterator var6 = driver.getUrlPrefixes().iterator(); while(var6.hasNext()) { String urlPrefix = (String)var6.next(); String prefix = ":" + urlPrefix + ":"; if (driver != UNKNOWN && urlWithoutPrefix.startsWith(prefix)) { return driver; } } } } return UNKNOWN; }
2)spring.datasource.*.driverClassName不替代也没有影响。
源码org.springframework.boot.autoconfigure.jdbc包中ConfigurationProperties.class文件反编译后,发明属性即为driverClassName字段,详细源码以下:
public String determineDriverClassName() { if (StringUtils.hasText(this.driverClassName)) { Assert.state(this.driverClassIsLoadable(), () -> { return "Cannot load driver class: " + this.driverClassName; }); return this.driverClassName; } else { ...
修正application.properties文件设置,参考信息以下:
spring.datasource.one.jdbc-url=jdbc:mysql://123.57.47.154:3306/springboot1 spring.datasource.one.username=root spring.datasource.one.password=wangyoodb spring.datasource.one.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.two.jdbc-url=jdbc:mysql://123.57.47.154:3306/springboot2 spring.datasource.two.username=root spring.datasource.two.password=wangyoodb spring.datasource.two.driver-class-name=com.mysql.cj.jdbc.Driver
引入话题
之前有群里的网友问Spring Boot中jdbc-url和url有什么区别?(题外话:关注微信民众号“Java精选”,留言切换工会总好背景发送音讯能够进群,群内只允许讨论手艺,完全免费,协助人人处理列位手艺困难。)
置信如今经由过程上述的剖析,人人应当很清晰了吧,二者是由于Spring Boot升级版本调整了源码,所以“url”参数被重新定名了。
至此集成mybatis完成多数据源的要领已完成,项目启动胜利后能够一般接见,经由过程浏览器接见输出以下信息:
[{"id":"1","name":"素文宅博客","detail":"迎接关注“Java精选”微信民众号,专注程序员推送一些Java开发学问,包含基础学问、各大盛行框架(Mybatis、Spring、Spring Boot等)、大数据手艺(Storm、Hadoop、MapReduce、Spark等)、数据库(Mysql、Oracle、NoSQL等)、算法与数据结构、口试专题、口试技能履历、职业规划以及优良开源项目等。"},{"id":"2","name":"素文宅博客导航","detail":"迎接关注“Java精选”微信民众号,一部份由小编总结整顿,另一部份来源于收集上优良资本,愿望对人人的进修和事情有所协助。"}]
运用JdbcTemplate
1、新增controller类文件
新增文件名JdbcTemplateController类文件,详细代码以下:
package com.yoodb.study.demo03; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import com.yoodb.study.demo03.bean.BootUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @RestController @RequestMapping("/jte") public class JdbcTemplateController { @Autowired private JdbcTemplate oneSqlSessionTemplate; @Autowired private JdbcTemplate twoSqlSessionTemplate; @RequestMapping("/getOneUsers") public List<Map<String, Object>> getOneUsers(){ String sql = "select * from boot_user"; List<Map<String, Object>> list = twoSqlSessionTemplate.queryForList(sql); for (Map<String, Object> map : list) { Set<Entry<String, Object>> entries = map.entrySet( ); if(entries != null) { Iterator<Entry<String, Object>> iterator = entries.iterator( ); while(iterator.hasNext( )) { Entry<String, Object> entry =(Entry<String, Object>) iterator.next( ); Object key = entry.getKey( ); Object value = entry.getValue(); System.out.println(key+":"+value); } } } return list; } @RequestMapping("/getTwoUsers") public List<BootUser> getTwoUsers() { List<BootUser> list = twoSqlSessionTemplate.query("select id,user_name " + "name,detail from boot_user", new BeanPropertyRowMapper<>(BootUser.class)); return list; } }
多数据源设置文件、多数据源类文件、实体类文件、controller层建立完成后,目次如图:
上述操纵完成后,由于集成mybatis时部份代码已存在(设置多数据源类文件),所以运用JdbcTemplate设置完成。
2、项目启动
项目启动后接见多数据源一要求地点:
http://localhost:8080/jte/getOneUsers
经由过程浏览器接见输出以下信息:
[{"id":1,"user_name":"素文宅博客","password":"e10adc3949ba59abbe56e057f20f883e","role_name":"素文宅博客","detail":"迎接关注“Java精选”微信民众号,专注程序员推送一些Java开发学问,包含基础学问、各大盛行框架(Mybatis、Spring、Spring Boot等)、大数据手艺(Storm、Hadoop、MapReduce、Spark等)、数据库(Mysql、Oracle、NoSQL等)、算法与数据结构、口试专题、口试技能履历、职业规划以及优良开源项目等。"}]
项目启动后接见多数据源二要求地点:
http://localhost:8080/jte/getTwoUsers
经由过程浏览器接见输出以下信息:
[{"id":"1","name":"素文宅博客","detail":"迎接关注“Java精选”微信民众号,专注程序员推送一些Java开发学问,包含基础学问、各大盛行框架(Mybatis、Spring、Spring Boot等)、大数据手艺(Storm、Hadoop、MapReduce、Spark等)、数据库(Mysql、Oracle、NoSQL等)、算法与数据结构、口试专题、口试技能履历、职业规划以及优良开源项目等。"}]
Spring容器中JdbcTemplate供应了两种注入体式格局,一种是运用@Resource注解,直接经由过程byName的体式格局注入进来,别的一种就是@Autowired注解加上@Qualifier注解,二者联合起来,实际上也是byName。
注重:
将JdbcTemplate注入胜利后,oneSqlSessionTemplate和twoSqlSessionTemplate此时就代表操纵差别的数据源,运用差别的JdbcTemplate操纵差别的数据源,完成了多数据源设置。
至此,Spring Boot集成MyBatis和运用JdbcTemplate两种体式格局多数据源设置完成,下面人人有什么问题迎接留言批评。
.NET Core 获取程序运行环境信息与反射的应用