spring+mybatis管理多個數據源(非分布式事務)


本文通過一個demo,介紹如何使用spring+mybatis管理多個數據源,注意,本文的事務管理並非之前博文介紹的分布式事務。

這個demo將使用兩個事務管理器分別管理兩個數據源。對於每一個獨立的事務,只涉及一個數據源。

demo功能:實現一個能依靠兩個獨立的事務管理器互不干涉的管理自己的數據源的web demo。

demo將實現:

1.獨立地控制兩個不同的數據源的事務管理器。

 

測試方式:restful web api

 

使用工具:

spring 4.1.1.RELEASE

mybatis 3.2.7

tomcat 7

 

在mysql中建立兩個schema,分別為dev和qa。並在里面分別建立一張名字表。

schema:dev

table:namaDev

id | nameDev

 

scheme:qa

table:nameQa

id  |  nameQa

對應的sql為

 1 CREATE SCHEMA `qa` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ;  2 CREATE SCHEMA `dev` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ;  3 
 4  CREATE  TABLE `dev`.`nameDev` (  5   `id` BIGINT NOT NULL AUTO_INCREMENT ,  6   `nameDev` VARCHAR(45) NULL ,  7   PRIMARY KEY (`id`) ,  8   UNIQUE INDEX `id_UNIQUE` (`id` ASC) );  9 
10   CREATE  TABLE `qa`.`nameQa` ( 11   `id` BIGINT NOT NULL AUTO_INCREMENT , 12   `nameQa` VARCHAR(45) NULL , 13   PRIMARY KEY (`id`) , 14   UNIQUE INDEX `id_UNIQUE` (`id` ASC) );
create sql

代碼分析:

本項目使用spring框架,因此首先配置相關bean

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3  xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
 4  xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
 5  xmlns:rabbit="http://www.springframework.org/schema/rabbit"
 6  xmlns:cache="http://www.springframework.org/schema/cache" xmlns:task="http://www.springframework.org/schema/task"
 7  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit.xsd  8  http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">
 9     <context:component-scan base-package="com.xy">
10         <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
11     </context:component-scan>
12     <context:property-placeholder location="classpath:context/database.properties"/>
13     <tx:annotation-driven/>
14 
15     <bean id="qadataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
16  destroy-method="close">
17         <property name="jdbcUrl" value="${qa.db.url}"></property>
18         <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
19         <property name="user" value="${qa.db.user}"></property>
20         <property name="password" value="${qa.db.password}"></property>
21         <property name="maxPoolSize" value="20"></property>
22         <property name="minPoolSize" value="20"></property>
23         <property name="initialPoolSize" value="20"></property>
24         <property name="maxIdleTime" value="200"></property>
25         <!--<property name="numHelperThreads" value="50"></property>-->
26     </bean>
27 
28     <bean id="devdataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
29  destroy-method="close">
30         <property name="jdbcUrl" value="${dev.db.url}"></property>
31         <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
32         <property name="user" value="${dev.db.user}"></property>
33         <property name="password" value="${dev.db.password}"></property>
34         <property name="maxPoolSize" value="20"></property>
35         <property name="minPoolSize" value="20"></property>
36         <property name="initialPoolSize" value="20"></property>
37         <property name="maxIdleTime" value="200"></property>
38         <!--<property name="numHelperThreads" value="50"></property>-->
39     </bean>
40 
41 
42 
43 
44 
45     <bean id="qasqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
46         <property name="dataSource" ref="qadataSource" />
47         <!--<property name="mapperLocations" value="classpath*:mapper/**/*.xml" />-->
48     </bean>
49 
50     <bean id="devsqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
51         <property name="dataSource" ref="devdataSource" />
52         <!--<property name="mapperLocations" value="classpath*:mapper/**/*.xml" />-->
53     </bean>
54 
55     <bean id="qaManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
56         <property name="dataSource" ref="qadataSource" />
57     </bean>
58 
59     <bean id="devManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
60         <property name="dataSource" ref="devdataSource" />
61     </bean>
62 
63 
64 
65     <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
66         <property name="basePackage" value="com.xy.dao"/>
67         <property name="sqlSessionFactoryBeanName" value="qasqlSessionFactory" />
68     </bean>
69 
70     <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
71         <property name="basePackage" value="com.xy.daodev"/>
72         <property name="sqlSessionFactoryBeanName" value="devsqlSessionFactory" />
73     </bean>
74 
75 
76 </beans>

其中qadataSource和devdataSource是對應兩個數據庫的數據源,qasqlSessionFactory和devsqlSessionFactory是mybatis的sessionfactory,兩個MapperScannerConfigurer自動將不同數據源的sql語句文件與interface自動裝配起來。qaManager與devManage分別管理qadataSource和devdataSource的事務,互不干涉。

Model類如下:package com.xy.model

package com.xy.model; /** * Created by helloworld on 2015/1/30. */
public class NameDev { private long id; private String nameDev; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getNameDev() { return nameDev; } public void setNameDev(String nameDev) { this.nameDev = nameDev; } }
NameDev
 1 package com.xy.model;  2 
 3 /**
 4  * Created by helloworld on 2015/1/30.  5  */
 6 public class NameQa {  7     private long id;  8     private String nameQa;  9 
10     public long getId() { 11         return id; 12  } 13 
14     public void setId(long id) { 15         this.id = id; 16  } 17 
18     public String getNameQa() { 19         return nameQa; 20  } 21 
22     public void setNameQa(String nameQa) { 23         this.nameQa = nameQa; 24  } 25 }
NameQa

qa數據源的mybatis mapper接口 package com.xy.dao

 1 package com.xy.dao;  2 
 3 import com.xy.model.NameQa;  4 
 5 /**
 6  * Created by helloworld on 2015/1/30.  7  */
 8 public interface NameQaMapper {  9     int insert(NameQa nameQa); 10 }
NameQaMapper

dev數據源的mybatis mapper接口 package com.xy.devdao

 1 package com.xy.daodev;  2 
 3 import com.xy.model.NameDev;  4 
 5 /**
 6  * Created by helloworld on 2015/1/30.  7  */
 8 public interface NameDevMapper {  9     int insert(NameDev nameDev); 10 }
NameDevMapper

處理事務的service

 1 package com.xy.service;  2 
 3 import com.xy.dao.NameQaMapper;  4 import com.xy.daodev.NameDevMapper;  5 import com.xy.model.NameDev;  6 import com.xy.model.NameQa;  7 import org.springframework.beans.factory.annotation.Autowired;  8 import org.springframework.stereotype.Service;  9 import org.springframework.transaction.annotation.Transactional; 10 
11 /**
12  * Created by helloworld on 2015/1/30. 13  */
14 @Service 15 public class NameService { 16  @Autowired 17  NameQaMapper nameQaMapper; 18  @Autowired 19  NameDevMapper nameDevMapper; 20 
21     @Transactional(value = "qaManager", rollbackFor = Exception.class) 22     public void addQa(boolean withQaException) throws Exception { 23         NameQa nameQa = new NameQa(); 24         nameQa.setNameQa("hello"); 25  nameQaMapper.insert(nameQa); 26 
27         if(withQaException){ 28             throw new Exception(); 29  } 30  } 31 
32     @Transactional(value = "devManager", rollbackFor = Exception.class) 33     public void addDev(boolean withDevException) throws Exception { 34         NameDev nameDev = new NameDev(); 35         nameDev.setNameDev("hello"); 36  nameDevMapper.insert(nameDev); 37 
38         if(withDevException){ 39             throw new Exception(); 40  } 41  } 42 
43 }
NameService

controller代碼

 1 package com.xy.controller;  2 
 3 import com.xy.service.NameService;  4 import org.springframework.beans.factory.annotation.Autowired;  5 import org.springframework.stereotype.Controller;  6 import org.springframework.ui.ModelMap;  7 import org.springframework.web.bind.annotation.RequestMapping;  8 import org.springframework.web.bind.annotation.RequestMethod;  9 import org.springframework.web.bind.annotation.RequestParam; 10 
11 /**
12  * Created by helloworld on 2014/11/22. 13  */
14 @Controller 15 public class mybatisController { 16 
17  @Autowired 18  NameService nameService; 19 
20     @RequestMapping(value = "/addName", method = RequestMethod.POST) 21     ModelMap addName(@RequestParam("withDevException") boolean withDevException, 22                      @RequestParam("witQaException") boolean witQaException ) { 23         try { 24  nameService.addDev(withDevException); 25         } catch (Exception e) { 26  e.printStackTrace(); 27  } 28 
29         try { 30  nameService.addQa(witQaException); 31         } catch (Exception e) { 32  e.printStackTrace(); 33  } 34         return new ModelMap("true"); 35  } 36 
37 
38 }
controller

將項目打成war包,命名為mybatis.war部署在tomcat上。

測試:

1.POST  http://localhost:8080/mybatis/addName.json

request parameters:
withDevException=false
witQaException=false
返回:true 兩個數據都添加成功

2.POST  http://localhost:8080/mybatis/addName.json

request parameters:
withDevException=false
witQaException=true
返回:true 只有dev添加成功
源碼下載:http://files.cnblogs.com/files/rain-in-sun/springmvc-mybatis-multidatasource.rar


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM