DB数据源之SpringBoot+MyBatis踏坑过程(二)手工配置数据源与加载Mapper.xml扫描
liuyuhang原创,未经允许进制转载
吐槽之后应该有所改了,该方式可以作为一种过渡方式来使用。
系列目录连接
DB数据源之SpringBoot+Mybatis踏坑过程实录(一)
1.环境说明
- 初次使用springboot,时间有限,需要迅速搭建好架构,没有时间研究
- 使用springboot过程中数据源无法获取;
- 使用springboot过程中注解莫名其妙失效;
- 用springboot过程中因为版本不懂,不扫描application.properties;
- 使用springboot过程中因为版本不懂,不扫描mybatis的mapper.xml包;
- springboot或spring注解使用十分不习惯或者还没有来得及深入学习的情况;
假设有以上问题,又时间紧迫,建议使用本文手工配置方式!!
springboot,parent 2.0.2.和1.5.3.都已经测试过,
在java8和java7环境下测试过。前者配java8,后者配java7,
使用MyEclipse 2017 C1 64x,MyEclipse 2016之前的版本无法使用java8
pom.xml核心如下:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.2.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <dependencies> <!-- 添加MySQL依赖 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- 添加JDBC依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!-- mybaits基础依赖 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.0</version> </dependency> <!-- mybatis插件依赖 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.1.1</version> </dependency> <!-- mapper依赖 --> <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper</artifactId> <version>3.3.7</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
2.配置思路
2.1.手工获取application.properties文件中的属性;
2.2.创建数据源DataSource;
2.3.注入数据源属性;
2.4.创建SqlSessionFactory;
2.5.SqlSessionFactory配置DataSource;
2.6.SqlSessionFactory配置扫描MyBatis-config.xml文件;
2.7.SqlSessionFactory配置扫描Mapper.xml所在包;
2.8.获取session查询数据库进行测试;
3.所需类与结构
3.0.application.properties文件与相应内容作为数据源;
3.1.SysConfig类,用于获取application.properties中的property;
3.2.DataConfig类,用于获取SqlSessionFactory;
3.3.ExampleController类,用于测试;
3.4.AppRun类,springboot的启动入口,将DataConfig初始化;
3.5.mapper.xml内容
4.代码
4.0.application.properties部分内容段落:
1 master.url=jdbc:mysql://qqq.jjj.xxx.iii:3306/master?characterEncoding=utf8 2 master.username=root 3 master.password=root 4 master.driver=com.mysql.jdbc.Driver 5 #master.driver-class-name=com.mysql.jdbc.Driver 一般是使用这个命名模式
4.1.SysConfig类,代码如下:
1 package com.FM.config; 2 3 import java.io.IOException; 4 import java.util.Properties; 5 6 import org.springframework.context.annotation.Configuration; 7 import org.springframework.core.io.ClassPathResource; 8 import org.springframework.core.io.Resource; 9 import org.springframework.core.io.support.PropertiesLoaderUtils; 10 11 /** 12 * 用于读取properties的类,基础配置文件名为application.properties,置于resources根目录下 13 * @author Liuyuhang 14 */ 15 public class SysConfig { 16 17 private Properties properties; 18 19 /** 20 * 修改无参构造,默认该类实例化的时候,加载配置文件中的内容,不做单例,因为配置文件可能更改 21 */ 22 public SysConfig() { 23 try { 24 Resource resource = new ClassPathResource("/application.properties"); 25 properties = PropertiesLoaderUtils.loadProperties(resource); 26 } catch (IOException e) { 27 e.printStackTrace(); 28 } 29 } 30 31 /** 32 * 获取属性,传入参数key 33 */ 34 public String getProperty(String key) { 35 return properties.getProperty(key); 36 } 37 }
4.2.DataSourceConfig类,代码如下:
1 package com.FM.config; 2 3 import java.util.HashMap; 4 5 import javax.sql.DataSource; 6 7 import org.apache.ibatis.session.SqlSessionFactory; 8 import org.mybatis.spring.SqlSessionFactoryBean; 9 import org.springframework.boot.jdbc.DataSourceBuilder; 10 import org.springframework.core.io.DefaultResourceLoader; 11 import org.springframework.core.io.Resource; 12 import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 13 /** 14 * DataConfig,获取数据源,配置给SqlSessionFactory,并以此获取session 15 * 16 * @author liuyuhang 17 */ 18 public class DataConfig { 19 /** 20 * 缓存factory的map,作为单例SessionFactory存储 21 */ 22 public static HashMap<String, SqlSessionFactory> factoryMap = new HashMap<String, SqlSessionFactory>(); 23 24 /** 25 * 构造器对缓存中的factory只实例化一次 26 * 不保证该单例能顺利执行,若看出问题,自行更改 27 * @throws Exception 28 */ 29 public DataConfig() { 30 System.out.println("out init sessionFactory:" + factoryMap); 31 if (factoryMap.isEmpty()) { 32 synchronized (factoryMap) { 33 if (factoryMap.isEmpty()) { 34 try { 35 SqlSessionFactory sessionFactory = getSessionFactory(); 36 factoryMap.put("master", sessionFactory); 37 System.out.println("in init sessionFactory:" + factoryMap); 38 } catch (Exception e) { 39 System.out.println("该错误比较严重,出现在数据源无参构造函数中!!"); 40 e.printStackTrace(); 41 } 42 43 } 44 } 45 46 } 47 48 } 49 50 /** 51 * 手动获取sessionFactory用例 52 * @param dataSourcePerfix 53 * @return 54 * @throws Exception 55 */ 56 public SqlSessionFactory getSessionFactory() throws Exception { 57 SysConfig sc = new SysConfig(); 58 String masterUrl = sc.getProperty("master.url"); 59 String masterDriver = sc.getProperty("master.driver"); 60 String masterUsername = sc.getProperty("master.username"); 61 String masterPassword = sc.getProperty("master.password"); 62 // 创建数据源 63 DataSourceBuilder create = DataSourceBuilder.create(); 64 create.url(masterUrl); 65 create.driverClassName(masterDriver); 66 create.username(masterUsername); 67 create.password(masterPassword); 68 DataSource source = create.build(); 69 // 创建sessionFactory 70 SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); 71 factoryBean.setDataSource(source);// 加载数据源 72 // 扫描mapper.xml 73 Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath:com/FM/mapper/*.xml"); 74 factoryBean.setMapperLocations(resources); 75 // 读取config 76 factoryBean.setConfigLocation(new DefaultResourceLoader().getResource("classpath:mybatis-config.xml")); 77 SqlSessionFactory sessionFactory = factoryBean.getObject(); 78 return sessionFactory; 79 } 80 81 }
4.3.ExampleController类,代码如下:
1 package com.FM.controller; 2 3 import java.util.HashMap; 4 import java.util.List; 5 import java.util.Map; 6 7 import javax.servlet.http.HttpServletRequest; 8 9 import org.apache.ibatis.session.SqlSession; 10 import org.apache.ibatis.session.SqlSessionFactory; 11 import org.springframework.web.bind.annotation.RequestMapping; 12 import org.springframework.web.bind.annotation.RestController; 13 14 import com.FM.config.DataConfig; 15 16 /** 17 * Controler用于测试 18 * @author liuyuhang 19 */ 20 @RestController //等同于responseBody + controller双重注解 21 public class ExampleController { 22 23 /** 24 * 手动创建session查询数据库用例,该方法可以创建多个sessionFactory,用多线程 25 * @param request 26 * @return 27 * @throws Exception 28 */ 29 @RequestMapping("/helloMybatis") 30 public List helloMybatis(HttpServletRequest request) throws Exception { 31 //数据源配置无参构造器 32 DataConfig dc = new DataConfig(); 33 SqlSessionFactory sessionFactory = dc.getSessionFactory();//获取sessionfactory 34 SqlSession session = sessionFactory.openSession();//获取session 35 List<Object> selectList = session.selectList("com.FM.mapper.MySqlMapper.getUser"); 36 return selectList;//自动转换为json 37 } 38 }
4.4.AppRun类,代码如下:
1 package com.FM; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.SpringBootConfiguration; 5 import org.springframework.boot.autoconfigure.SpringBootApplication; 6 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; 7 import org.springframework.boot.web.servlet.ServletComponentScan; 8 9 import com.FM.config.DataConfig; 10 11 @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) // 禁用默认的单数据源配置 12 @SpringBootConfiguration // springboot基础配置注解 13 @ServletComponentScan // springboot servlet filter 14 // @EnableConfigurationProperties//该注解于springboot1.5以上废弃 15 public class AppRun { 16 17 public static void main(String[] args) throws Exception { 18 SpringApplication.run(AppRun.class, args); 19 DataConfig dc = new DataConfig();//初始化配置 20 21 } 22 }
4.5.mapper.xml内容
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > 3 <mapper namespace="com.FM.mapper.MySqlMapper"> 4 <!-- 随便写作为测试而已 --> 5 <resultMap id="getUserMap" type="java.util.Map"> 6 <result column="id" property="id" jdbcType="INTEGER" javaType="int" /> 7 <result column="username" property="username" jdbcType="VARCHAR" javaType="String" />< 8 <result column="password" property="password" jdbcType="VARCHAR" javaType="String" /> 9 </resultMap> 10 <select id="getUser" parameterType="java.util.Map" resultMap="getUserMap"> 11 select * from user 12 </select> 13 </mapper>
5.测试
启动后控制台显示如下:
浏览器输入 http://localhost:8080/helloMybatis
控制台结果如下图:
页面结果如下图:
6.总结
spring注解一直是我饿心结,当我想将我的代码改成以注解方式来进行装配注入的时候,总是不行的,
于是乎我学会了很多奇葩的手段,可能不主流。
吐槽归吐槽,学习归学习,工作归工作,一码是一码!!!
注:本文配置方式会产生几个问题
要确保手动加载mapper.xml的扫描只扫描一次,否则是否会加载产生多个mapper加入VM管理并不确定,很可能数量很多。
springboot以这种方式配置的数据源,本质上是交给内置的tomcat来管理的,内置的tomcat来管理会涉及到连接池的问题。
如果数据库对于连接数量没有扩容,而内置tomcat的连接池没有配置,短时间内会产生大量连接而不销毁,会导致连接
拒绝,而报错。
可能报出的两个常见的错误,主要内容如下:
a:Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
The last packet successfully received from the server was 14,595,596 milliseconds ago. The last packet sent successfully to the server was 14,595,612 milliseconds ago.
该错误的原因通常是因为session没有保证关闭引起的
b: o.a.tomcat.jdbc.pool.ConnectionPool : Unable to create initial connections of pool.
Data source rejected establishment of connection, message from server: "Too many connections"
本示例中使用的是MySql数据库,Threads_connected设置的数值是512,因此报上述错误。
该错误的原因不仅有Mysql数据库优化的问题,同时也有连接池管理配置的问题
以上列举问题将在后文中处理,更新后将在文尾插入连接!
对于以上配置过程的springBoot的注解版,明日再更
休息!
以上!