DB數據源之SpringBoot+MyBatis踏坑過程(二)手工配置數據源與加載Mapper.xml掃描html
liuyuhang原創,未經容許進制轉載 java
吐槽以後應該有所改了,該方式能夠做爲一種過渡方式來使用。mysql
系列目錄鏈接web
DB數據源之SpringBoot+Mybatis踏坑過程實錄(一)spring
1.環境說明sql
假設有以上問題,又時間緊迫,建議使用本文手工配置方式!!數據庫
springboot,parent 2.0.2.和1.5.3.都已經測試過,apache
在java8和java7環境下測試過。前者配java8,後者配java7,json
使用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的註解版,明日再更
休息!
以上!