Spring uses Abstractroutingdatasource to customize transaction handling problems when dynamic Data sources are customized

Source: Internet
Author: User
Tags aop delete key


Recently saw a blog on the Internet, inheriting the spring abstractroutingdatasource definition of their own dynamic data source, you can dynamically switch to different database data sources, it is easy to use.

Import Org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
 * Custom dynamic routed data source inherits from spring JDBC Abstractroutingdatasource * * 
 @author 
 * *
 /Public
class Dbroutedatasource extends Abstractroutingdatasource {

	/**
	 * Gets the key that is associated with the data source
	 This key is map<string, The key value bound to the data source in datasource> resolveddatasources
	 * used when obtaining the target data source via Determinetargetdatasource *
	Override
	protected Object Determinecurrentlookupkey () {return
		
		routeholder.getroutekey ();
	}

}

The key that stores the data source used by the current thread through the container Routeholder

/** *
 Save the current thread data source key
 * @author 
 * @version 1.0 * */Public
class Routeholder {
	private static threadlocal<string> Routekey = new threadlocal<string> ();
	
	/**
	 * Get the current thread's data source route key
	 * @return
	/public static string Getroutekey ()
	{
		string key = Routekey.get ();
		Return key;
	}
	/**
	 * Binding the
	 Removeroutekey () method must be called to delete the
	 * @param key/public
	static void when the key * usage of the frontline data source route is complete  Setroutekey (String key)
	{
		routekey.set (key);
	}
	
	/**
	 * Delete key/public
	static void Removeroutekey ()
	{
		routekey.remove (
	) for the current thread-bound data source route
}


Use spring's AOP programming to parse the data source key from the custom annotation @datasource in the business logic method and add it to routeholder before the business logic method runs using the key of the data source

/**
 * The slice before executing the DAO method
 * Gets the DataSource object's key
 * @author Administrator to specify the current thread data source route to Routeholder
 Public
class Datasourceaspect
{
	/**
	 * Specifies the key/public void Beforedaomethod for the current thread data source route in the section before obtaining the DataSource object before the DAO layer method
	(joinpoint Point)
	{
		The annotations configured on the//dao method
		DataSource DataSource = ((methodsignature) point.getsignature ()). GetMethod () . Getannotation (Datasource.class);
		Routeholder.setroutekey (Datasource.value ());
		
	}

Business logic Methods

@Named ("UserService") Public
class UserService 
{
	@Inject
	private Userdao Userdao;
	
	@DataSource ("master")
	@Transactional (propagation=propagation.required) public
	void updatepasswd (int Userid,string passwd)
	{
		User user = new user ();
		User.setuserid (userid);
		User.setpassword (passwd);
		Userdao.updatepassword (user);
	}
	@DataSource ("slave")
	@Transactional (propagation=propagation.required) public
	User getuser (int userid)
	{
		User user = Userdao.getuserbyid (userid);
		SYSTEM.OUT.PRINTLN ("username------:" +user.getusername ());
		return user;
	}


Spring's configuration file

<bean id= "DataSource" class= "Com.westone.datasource.DbRouteDataSource" > <property name= "targetdatasources"
				   "> <map> <!--write--> <entry key=" master "value-ref=" master "></entry> <!--read--> <entry key= "slave" value-ref= "slave" ></entry> </map> </property&gt	
	; </bean> <bean id= "master" class= "Org.apache.commons.dbcp.BasicDataSource" > <property name= "D  
        Riverclassname "value=" ${jdbc.driverclass} "/> <property name=" url "value=" ${jdbc.masterurl} "/> <property name= "username" value= "${jdbc.username}"/> <property name= "password" value= Ord} "/> <property name= maxactive" value= "${jdbc.maxactive}" ></property> <property Name= "Maxidle" value= "${jdbc.maxidle}" ></property> <property name= "maxwait" value= "${jdbc.maxwait}" &  
   Gt;</property> </bean> <bean id= "slave" class= "Org.apache.commons.dbcp.BasicDataSource" > <property n  
        Ame= "Driverclassname" value= "${jdbc.driverclass}"/> <property name= "url" value= "${jdbc.slaveurl}"/> <property name= "username" value= ${jdbc.username} "/> <property name=" password "value=". Password} "/> <property name= maxactive" value= "${jdbc.maxactive}" ></property> <prop Erty name= "Maxidle" value= "${jdbc.maxidle}" ></property> <property name= "maxwait" value= "${jdbc.maxwa" It} "></property> </bean> <bean id=" sqlsessiontemplate "class=" Org.mybatis . Spring. Sqlsessiontemplate "> <constructor-arg index=" 0 "ref=" sqlsessionfactory "/> </bean> <b Ean id= "sqlsessionfactory" class= "Org.mybatis.spring.SqlSessionFactoryBean" > <property name= "Configlocatio" N "value=" CLASSPAth:config/mybatis/mybatis.cfg.xml "></property> <property name=" DataSource "ref=" DataSource "/>" </bean> <!--Configure Mapper the mapping scanner automatically generates DAO implementation classes--> <bean class= According to the interfaces defined in the package Org.mybatis.spring.map Per. Mapperscannerconfigurer "> <property name=" basepackage "value=" Com.westone.dao "></property> </b Ean> <!--parsing @datasource annotations for the business logic layer inject the routeholder of the current thread into the data source key--> <bean id= "Aspectbean" Com.westone.datasource.aspect.DataSourceAspect "></bean> <aop:config> <aop:aspect id=" DataS Ourceaspect "ref=" Aspectbean "> <aop:pointcut id=" datasourcepoint "expression=" Execution (Public * Com.weston E.service.*.* (..)) " /> <aop:before method= "Beforedaomethod" pointcut-ref= "Datasourcepoint"/> </aop:aspect> &l The t;/aop:config> <!--transaction manager configures--> <bean id= "TransactionManager class=" Org.springframework.jdbc.DataSource. Datasourcetransactionmanager "> <property name=" dataSource "ref=" DataSource "/> </bean> &l t;! --Open the transaction annotation driver to use @transactional annotation for business logic layer to manage transaction--> <tx:annotation-driven transaction-manager= "Transactio Nmanager "/>

The transaction management configuration must be configured to could not open JDBC Connection for transaction before injecting the data source key into Routeholder. Nested exception is java.lang.IllegalStateException:Cannot determine target DataSource for lookup key [null] No data source error found


Finally, the method of testing the business logic layer discovers that a different data source key can be configured with a dynamic data source based on the @datasource ("master") annotation on the method. There is no need to define different data source objects in the business logic method layer and manipulate the data artificially using different data sources.




Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.