项目采用的是struts2+spring+ibatis架构,下面是关键部分代码:
applicationContext.xml:
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xmlns:tx="http://www.springframework.org/schema/tx"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-2.5.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
- http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"
- default-autowire="byName" default-lazy-init="false">
- <context:component-scan base-package="com.ssi.*" />
- <!-- 属性文件读入 -->
- <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
- <property name="locations">
- <list>
- <value>classpath*:jdbc.properties</value>
- </list>
- </property>
- </bean>
- <!-- 配置sqlMapclient -->
- <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
- <property name="configLocation" value="classpath:ibatis-sqlmap-config.xml" />
- <property name="dataSource" ref="dataSource" />
- </bean>
- <bean id="sqlMapClient1" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
- <property name="configLocation" value="classpath:ibatis-sqlmap-config.xml" />
- <property name="dataSource" ref="db1" />
- </bean>
- <bean id="sqlMapClient2" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
- <property name="configLocation" value="classpath:ibatis-sqlmap-config.xml" />
- <property name="dataSource" ref="db2" />
- </bean>
- <bean id="sqlMapClientCenter" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
- <property name="configLocation" value="classpath:ibatis-sqlmap-config.xml" />
- <property name="dataSource" ref="center" />
- </bean>
- <bean id="dynamicSqlMapClientDaoSupport" class="com.ssi.dao.DynamicSqlClientDaoSupport">
- <property name="targetSqlMapClients">
- <map>
- <entry key="db1" value-ref="sqlMapClient1" />
- <entry key="db2" value-ref="sqlMapClient2" />
- <entry key="center" value-ref="sqlMapClientCenter" />
- </map>
- </property>
- <property name="defaultSqlMapClient" ref="sqlMapClientCenter" />
- </bean>
- <bean id="ibatisDaoSupport" class="com.ssi.dao.IbatisDaoSupport" parent="dynamicSqlMapClientDaoSupport"></bean>
- <bean id="userDao" class="com.ssi.dao.impl.UserDaoImpl" parent="ibatisDaoSupport"></bean>
- <!-- 支持 @AspectJ 标记-->
- <aop:aspectj-autoproxy proxy-target-class="true"/>
- <!-- 配置JTA的事务管理器 -->
- <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close">
- <property name="forceShutdown" value="true" />
- </bean>
- <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
- <property name="transactionTimeout" value="300" />
- </bean>
- <bean id="springTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
- <property name="transactionManager" ref="atomikosTransactionManager" />
- <property name="userTransaction" ref="atomikosUserTransaction" />
- </bean>
- <!-- 配置通知 -->
- <tx:advice id="txAdvice" transaction-manager="springTransactionManager">
- <tx:attributes>
- <tx:method name="*" rollback-for="Exception,RuntimeException,com.ssi.exception.SystemException" propagation="REQUIRED" />
- </tx:attributes>
- </tx:advice>
- <!-- 以AspectJ方式 定义 AOP -->
- <aop:config>
- <aop:advisor pointcut="execution(* com.ssi.service..*Service*.*(..))" advice-ref="txAdvice" />
- </aop:config>
- <!-- spring 定时器任务开始 -->
- <bean name="job" class="org.springframework.scheduling.quartz.JobDetailBean">
- <property name="jobClass">
- <value>com.ssi.action.TimerAction</value>
- </property>
- <property name="jobDataAsMap">
- <map>
- <!-- timeout属性设定了当服务器启动后过10秒钟首次调用你的JobAction -->
- <entry key="timeout">
- <value>10</value>
- </entry>
- </map>
- </property>
- </bean>
- <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
- <property name="jobDetail">
- <ref bean="job"/>
- </property>
- <property name="cronExpression">
- <value>0 53 15 ? * MON-FRI</value>
- </property>
- </bean>
- <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean" autowire="no">
- <property name="triggers">
- <list>
- <ref local="cronTrigger"/>
- </list>
- </property>
- </bean>
- <!-- spring 定时器任务结束 -->
- </beans>
applicationContext-datasource.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xmlns:tx="http://www.springframework.org/schema/tx"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
- <!--指定Spring配置中用到的属性文件-->
- <bean id="propertyConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
- <property name="locations">
- <list>
- <value>classpath:jdbc.properties</value>
- </list>
- </property>
- </bean>
- <!-- JTA 数据源配置 -->
- <bean id="center" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
- <property name="uniqueResourceName">
- <value>mysql/center</value>
- </property>
- <property name="xaDataSourceClassName">
- <value>${jta.driver.className}</value>
- </property>
- <property name="xaProperties">
- <props>
- <prop key="url">${center.jdbc.driver.url}</prop>
- <prop key="user">${center.sql.user.name}</prop>
- <prop key="password">${center.sql.user.password}</prop>
- </props>
- </property>
- <property name="testQuery" value="select 1" />
- <property name="poolSize">
- <value>${poolsize}</value>
- </property>
- <property name="maxPoolSize">
- <value>${maxPoolSize}</value>
- </property>
- <property name="borrowConnectionTimeout"><value>${borrowConnectionTimeout}</value></property>
- </bean>
- <bean id="db1" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
- <property name="uniqueResourceName">
- <value>mysql/db1</value>
- </property>
- <property name="xaDataSourceClassName">
- <value>${jta.driver.className}</value>
- </property>
- <property name="xaProperties">
- <props>
- <prop key="url">${db1.jdbc.driver.url}</prop>
- <prop key="user">${company.sql.user.name}</prop>
- <prop key="password">${company.sql.user.password}</prop>
- </props>
- </property>
- <property name="testQuery" value="select 1" />
- <property name="poolSize">
- <value>${poolsize}</value>
- </property>
- <property name="maxPoolSize">
- <value>${maxPoolSize}</value>
- </property>
- <property name="borrowConnectionTimeout"><value>${borrowConnectionTimeout}</value></property>
- </bean>
- <bean id="db2" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
- <property name="uniqueResourceName">
- <value>mysql/db2</value>
- </property>
- <property name="xaDataSourceClassName">
- <value>${jta.driver.className}</value>
- </property>
- <property name="xaProperties">
- <props>
- <prop key="url">${db2.jdbc.driver.url}</prop>
- <prop key="user">${company.sql.user.name}</prop>
- <prop key="password">${company.sql.user.password}</prop>
- </props>
- </property>
- <property name="testQuery" value="select 1" />
- <property name="poolSize">
- <value>${poolsize}</value>
- </property>
- <property name="maxPoolSize">
- <value>${maxPoolSize}</value>
- </property>
- <property name="borrowConnectionTimeout"><value>${borrowConnectionTimeout}</value></property>
- </bean>
- <bean id="dataSource" class="com.ssi.datasource.DynamicDataSource">
- <property name="targetDataSources">
- <map key-type="java.lang.String">
- <entry key="db1" value-ref="db1" />
- <entry key="db2" value-ref="db2" />
- <entry key="center" value-ref="center" />
- </map>
- </property>
- <property name="defaultTargetDataSource" ref="center" />
- </bean>
- </beans>
DynamicSqlClientDaoSupport.java
- package com.ssi.dao;
- import java.util.Map;
- import javax.sql.DataSource;
- import org.springframework.beans.factory.InitializingBean;
- import org.springframework.dao.support.DaoSupport;
- import org.springframework.orm.ibatis.SqlMapClientTemplate;
- import org.springframework.util.Assert;
- import com.ibatis.sqlmap.client.SqlMapClient;
- import com.ssi.datasource.DbContextHolder;
- public class DynamicSqlClientDaoSupport extends DaoSupport implements InitializingBean{
- private SqlMapClientTemplate sqlMapClientTemplate = new SqlMapClientTemplate();
- private Map<String,SqlMapClient> targetSqlMapClients;
- private SqlMapClient defaultSqlMapClient;
- private boolean externalTemplate = false;
- /**
- * Set the JDBC DataSource to be used by this DAO.
- * Not required: The SqlMapClient might carry a shared DataSource.
- * @see #setSqlMapClient
- */
- public final void setDataSource(DataSource dataSource) {
- if (!this.externalTemplate) {
- this.sqlMapClientTemplate.setDataSource(dataSource);
- }
- }
- /**
- * Return the JDBC DataSource used by this DAO.
- */
- public final DataSource getDataSource() {
- return this.sqlMapClientTemplate.getDataSource();
- }
- /**
- * Set the iBATIS Database Layer SqlMapClient to work with.
- * Either this or a "sqlMapClientTemplate" is required.
- * @see #setSqlMapClientTemplate
- */
- public final void setSqlMapClient(SqlMapClient sqlMapClient) {
- if (!this.externalTemplate) {
- this.sqlMapClientTemplate.setSqlMapClient(sqlMapClient);
- }
- }
- /**
- * Return the iBATIS Database Layer SqlMapClient that this template works with.
- */
- public final SqlMapClient getSqlMapClient() {
- return this.sqlMapClientTemplate.getSqlMapClient();
- }
- /**
- * Set the SqlMapClientTemplate for this DAO explicitly,
- * as an alternative to specifying a SqlMapClient.
- * @see #setSqlMapClient
- */
- public final void setSqlMapClientTemplate(SqlMapClientTemplate sqlMapClientTemplate) {
- Assert.notNull(sqlMapClientTemplate, "SqlMapClientTemplate must not be null");
- this.sqlMapClientTemplate = sqlMapClientTemplate;
- this.externalTemplate = true;
- }
- /**
- * Return the SqlMapClientTemplate for this DAO,
- * pre-initialized with the SqlMapClient or set explicitly.
- */
- public final SqlMapClientTemplate getSqlMapClientTemplate() {
- String dbtype = DbContextHolder.getDbType();
- if(targetSqlMapClients!=null&&targetSqlMapClients.containsKey(dbtype)){
- SqlMapClient sqlMapClient = targetSqlMapClients.get(dbtype);
- sqlMapClientTemplate = new SqlMapClientTemplate(sqlMapClient);
- }
- return this.sqlMapClientTemplate;
- }
- @Override
- protected final void checkDaoConfig() {
- if (!this.externalTemplate) {
- this.sqlMapClientTemplate.afterPropertiesSet();
- }
- }
- public Map<String, SqlMapClient> getTargetSqlMapClients() {
- return targetSqlMapClients;
- }
- public void setTargetSqlMapClients(Map<String, SqlMapClient> targetSqlMapClients) {
- this.targetSqlMapClients = targetSqlMapClients;
- }
- public SqlMapClient getDefaultSqlMapClient() {
- return defaultSqlMapClient;
- }
- public void setDefaultSqlMapClient(SqlMapClient defaultSqlMapClient) {
- this.defaultSqlMapClient = defaultSqlMapClient;
- }
- }
IbatisDaoSupport.java
- package com.ssi.dao;
- import java.io.Serializable;
- import java.sql.SQLException;
- import java.util.List;
- import java.util.Map;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.springframework.orm.ibatis.SqlMapClientCallback;
- import com.ibatis.sqlmap.client.SqlMapExecutor;
- @SuppressWarnings("unchecked")
- public class IbatisDaoSupport<Entity> extends DynamicSqlClientDaoSupport implements IEntityDao<Entity> {
- protected final Log log = LogFactory.getLog(getClass());
- public Entity get(String sqlId, Serializable id) {
- return (Entity) getSqlMapClientTemplate().queryForObject(sqlId, id);
- }
- public Entity getByParamMap(String sqlId, Object param) {
- return (Entity) getSqlMapClientTemplate().queryForObject(sqlId, param);
- }
- public Object save(String sqlId, Object o) {
- return getSqlMapClientTemplate().insert(sqlId, o);
- }
- public Object batchSave(final String sqlId,final List<Entity> entityList) throws Exception{
- // 执行回调
- return getSqlMapClientTemplate().execute(new SqlMapClientCallback() {
- // 实现回调接口
- public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException{
- // 开始批处理
- executor.startBatch();
- for (Entity entity : entityList) {
- executor.insert(sqlId, entity);
- }
- return executor.executeBatch();
- }
- });
- }
- public Integer remove(String sqlId, Object o) {
- return getSqlMapClientTemplate().delete(sqlId, o);
- }
- public Integer removeById(String sqlId, Serializable id) {
- return getSqlMapClientTemplate().delete(sqlId, id);
- }
- public Integer update(String sqlId, Object o) {
- return getSqlMapClientTemplate().update(sqlId, o);
- }
- public Long totalCount(String sqlId, Object o){
- return (Long) getSqlMapClientTemplate().queryForObject(sqlId, o);
- }
- public List<Entity> pagedList(String sqlId, Map<String, Object> map,int pageSize, int pageNum) {
- int start = (pageNum - 1) * pageSize;
- map.put("start", start);
- map.put("pageSize", pageSize);
- List<Entity> list = getSqlMapClientTemplate().queryForList(sqlId, map);
- return list;
- }
- public List<Entity> list(String sqlId,Object o){
- return getSqlMapClientTemplate().queryForList(sqlId,o);
- }
- public List<Entity> list(String sqlId){
- return getSqlMapClientTemplate().queryForList(sqlId);
- }
- }
UserDaoImpl.java:
- package com.ssi.dao.impl;
- import org.springframework.stereotype.Repository;
- import com.ssi.dao.IUserDao;
- import com.ssi.dao.IbatisDaoSupport;
- import com.ssi.model.User;
- @Repository("userDao")
- public class UserDaoImpl extends IbatisDaoSupport<User> implements IUserDao {
- public Integer addUser(User user) throws Exception{
- return (Integer) this.save("User.insert", user);
- }
- }
UserServiceImpl.java
- package com.ssi.service.impl;
- import javax.annotation.Resource;
- import org.springframework.stereotype.Service;
- import com.ssi.dao.IUserDao;
- import com.ssi.datasource.DbContextHolder;
- import com.ssi.model.User;
- import com.ssi.service.IUserService;
- @Service("userService")
- public class UserServiceImpl implements IUserService {
- @Resource private IUserDao userDao;
- /**
- * 测试在service中切换数据源 异常是否回滚
- */
- public void addUser(User user) throws Exception{
- DbContextHolder.setDbType("db1");
- userDao.addUser(user);
- DbContextHolder.setDbType("db2");
- user.setUserName("user2");
- userDao.addUser(user);
- DbContextHolder.setDbType("center");
- user.setUserName("user3");
- userDao.addUser(user);
- //System.out.println(1/0);
- }
- }
DynamicDataSource.java:
- public class DynamicDataSource extends AbstractRoutingDataSource {
- static Logger log = Logger.getLogger(DynamicDataSource.class);
- protected Object determineCurrentLookupKey() {
- return DbContextHolder.getDbType();
- }
- }
DbContextHolder.java:
- public class DbContextHolder {
- private static final ThreadLocal contextHolder = new ThreadLocal();
- public static void setDbType(String dbType) {
- contextHolder.set(dbType);
- }
- public static String getDbType() {
- return (String) contextHolder.get();
- }
- public static void clearDbType() {
- contextHolder.remove();
- }
- }
三个数据库:dbcenter、db1、db2 表结构均相同
脚本:
- DROP TABLE IF EXISTS `tb_user`;
- CREATE TABLE `tb_user` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `userName` varchar(20) DEFAULT NULL,
- `password` varchar(60) DEFAULT NULL,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
单元测试:
- public class JunitTest{
- public ApplicationContext cxt;
- @Test
- public void init() throws Exception{
- cxt = new ClassPathXmlApplicationContext(new String[] {"applicationContext.xml","applicationContext-datasource.xml"});
- testInsertUser();
- }
- private void testInsertUser() throws Exception{
- IUserService userService = (IUserService)cxt.getBean("userService");
- User user = new User();
- user.setUserName("user1");
- user.setPassword("0");
- userService.addUser(user);
- }
- private void testInsertUser2() throws Exception{
- }
相关推荐
此外,为了在代码中切换数据源,通常会有一个数据源路由的策略,例如在Service层根据业务逻辑决定使用哪个数据源。这可能涉及到AOP(面向切面编程)的使用,通过注解或配置来切换数据源。 在实际开发中,多数据源的...
分布式数据源、数据源的动态查找以及分布式事务的实现是现代企业级应用中不可或缺的部分,尤其是在高并发、大数据量的场景下。本项目"spring-jta-mybatis"着重讲解了如何在Spring框架中结合JTA(Java Transaction ...
- 在`@Service`或`@Repository`类中,使用`@Autowired`注入`DataSource`,然后在方法内部使用`DynamicDataSourceRouter`切换数据源。 7. **测试与调试** - 可以编写单元测试或集成测试,模拟不同场景下的数据源...
在企业级应用开发中,数据源管理是至关重要的部分,特别...通过这个项目,你可以学习到如何在Spring、SpringMVC和Mybatis的环境下实现动态多数据源的配置和管理,这对于大型分布式系统的设计和开发具有很高的实践价值。
支持 多层数据源嵌套切换 。(ServiceA >>> ServiceB >>> ServiceC)。 提供 基于seata的分布式事务方案 。 支持 数据源分组 ,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。 支持数据库敏感配置信息 加
7. **动态数据源切换**:可以通过定义一个工具类或者Service,提供动态切换数据源的方法,根据业务需求在运行时切换数据源,例如切换到主库执行写操作,切换到从库执行读操作。 8. **测试**:在名为`test`的文件中...
这些数据源可以在事务管理中动态切换,以支持多数据源事务。这通常需要自定义事务管理器,比如使用`PlatformTransactionManager`的子类,来处理不同数据源的事务。 **5. 分布式事务处理**: JTA通过UserTransaction...
在Spring框架中整合多数据源是一项常见的需求,特别是在大型企业应用或者分布式系统中,往往需要连接不同的数据库以满足不同业务场景。本实例将详细介绍如何在Spring中实现这一功能。 首先,我们要理解“多数据源”...
Spring框架的多数据源支持非常完善,可以通过AbstractRoutingDataSource实现动态数据源切换,或者使用Spring Boot的MultiDataSource配置,根据业务需求灵活选择数据源。 再来看“线程池多线程访问”。线程池是Java...
在Spring Boot应用中,使用`spring-data-jpa`来配置MySQL多数据源是一项常见的需求,尤其是在构建大型分布式系统时,为了实现数据隔离、负载均衡或读写分离等目的。本教程将详细介绍如何在Spring Boot项目中配置多个...
6. **切换数据源**:在业务代码中,可以通过在Service层的方法上添加自定义注解来指定使用哪个数据源,或者在运行时动态切换数据源。 7. **事务管理**:对于多数据源环境,需要配置`PlatformTransactionManager`以...
4. **数据源路由**:为了实现数据源的动态切换,我们需要一个数据源路由类(`AbstractRoutingDataSource`),这个类可以根据一定的规则(比如事务上下文、请求参数等)动态选择使用哪个数据源。自定义数据源路由类并...
在这个例子中,`UseDataSource`是我们自定义的注解,用于标记需要切换数据源的方法。`DataSourceRouter`可能是一个服务,负责根据数据源键值来获取正确的`DataSource`实例。 接下来,我们讨论如何在Service或Dao层...
在Spring Boot应用中,多数据源配置是一项重要的技术实践,特别是在大型系统中,可能需要连接到多个数据库以实现数据隔离、读写分离或是分布式事务管理。Spring Boot以其强大的自动化配置能力,使得设置多数据源变得...
4. **动态数据源**: 动态数据源允许程序在运行时动态地切换数据源。在Spring Boot中,这通常通过`AbstractRoutingDataSource`实现,它可以基于某些条件(如线程绑定、请求上下文等)来决定使用哪个数据源。 5. **...
在Spring框架中,管理多个数据源是一项常见的任务,特别是在大型分布式系统中,可能需要连接到不同的数据库以实现数据隔离或优化性能。这篇博客主要探讨了如何在Spring中配置和管理多个数据源,以便灵活地处理不同的...
此外,如果需要在运行时动态切换数据源,可以使用AbstractRoutingDataSource,它允许你在运行时根据某种策略(如事务、线程本地变量等)决定使用哪个数据源。 在"spring-boot-jdbc多数据源的demo"中,`dbs`可能包含...
一个基于springboot的快速集成多数据源的启动器简介dynamic-datasource-spring-boot-starter是一个基于springboot的快速集成多数据源的启动器。其支持Jdk 1.7 +,SpringBoot 1.4.x 1.5.x 2.xx。文件| 文献资料|特性...
在Spring+Mybatis框架中,实现多个数据源的调用是一项常见的需求,特别是在大型系统或者分布式环境中,可能需要连接不同的数据库来处理不同的业务数据。以下是一个详细的多数据源配置和使用的指南。 首先,我们需要...
- **事务边界**:在Service层,使用`@Transactional`注解来声明事务边界,Spring会根据当前数据源自动进行事务管理。 4. **代码示例** 在Spring的XML配置文件中,可以这样配置: ```xml <!-- 配置数据源...