When we develop SaaS or mobile applications that involve multiple companies, each company is asked to use a single database, and how to configure the spring data source so that each company uses a different database connection.
1, the company ID is stored in a threadlocal variable, each time the request is set, so that each access to the data source can be obtained from the threadlocal the current request to the company ID.
/**
* The data used to hold the current thread *
/public class Threadholder {
//company ID
private static threadlocal<string> Localdid = new threadlocal<string> ();
public static void putsp (String sp) {
localdid.set (sp);
}
public static String getsp () {
if (localdid.get () = = null)
return "";
else
return (String) localdid.get ();
}
}
2. Call the Threadholder.putsp method on each request to set the company ID.
You can define a filter that is invoked in the Dofilter method to achieve the effect of each request setting. As for the company ID parameter where the client request is placed, this can be set flexibly and can be placed in each request parameter or in a cookie.
3. Modify the spring data source configuration
Original configuration (typically using the C0P3 data source configuration)
<bean id= "DataSource" class= "Com.mchange.v2.c3p0.ComboPooledDataSource" > <property name= "Driverclass" value= "xxxx"/> <property name= "jdbcurl" value= "xxx"/> <property name= "user" value= "user"/> <pro Perty name= "password" value= "password"/> <property name= "minpoolsize" value= "1"/> <property name= "MaxPoo Lsize "value=" "/> <property name=" maxidletime "value=" 25000 "/> <property name=" AcquireIncrement "Valu
e= "1"/> <property name= "maxstatements" value= "0"/> <property name= "initialpoolsize" value= "All"/> <property name= "Idleconnectiontestperiod" value= "18000"/> <property name= "acquireretryattempts" value= "10" /> <property name= "Acquireretrydelay" value= "$"/> <property name= "breakafteracquirefailure" value= "FA LSE "/> <property name=" checkouttimeout "value=" 10000 "/> <property name=" Testconnectiononcheckout "value= "False"/> </bean>
Modified to:
<bean id= "DataSource" class= "Com.sangfor.frame.multiclient.MultiClientDataSource" > <property name= " DataSource "> <ref bean=" datasourcedefault "/> </property> </bean> & Lt;bean id= "Datasourcedefault" class= "Com.mchange.v2.c3p0.ComboPooledDataSource" > <property name= " Driverclass "value=" xxxx "/> <property name=" jdbcurl "value=" xxx "/> <property name=" user "value=" user "/&
Gt <property name= "password" value= "password"/> <property name= "minpoolsize" value= "1"/> <property name= "Maxpoolsize" value= "/>" <property name= "MaxIdleTime" value= "+"/> <property name= "AcquireIncrement" value= "1"/> <property name= "maxstatements" value= "0"/> <property name= "initialpoolsize" value= "All"/&G
T <property name= "idleconnectiontestperiod" value= "/> <property name=" acquireretryattempts "value=" 10 "/ > <property name= "AcquirEretrydelay "value=" "/> <property name=" Breakafteracquirefailure "value=" false "/> <property name=" ch
Eckouttimeout "value=" 10000 "/> </bean>
Multiclientdatasource:
public class Multiclientdatasource implements DataSource {public static final String Dbname_prefix = "Client_";
Private Combopooleddatasource dataSource = null;
Private map<string,datasource> DsMap = new hashmap<string,datasource> ();
Private static Object Lock=new object (); Public DataSource AddDatasource (String do) {try{synchronized (lock) {if (dsmap==null) DsMap = new HashMap
<String,DataSource> ();
DataSource ds = Dsmap.get (did);
if (ds! = null) return DS;
Combopooleddatasource Newds = Getnewdatasource (did);
Dsmap.put (did, Newds);
}}catch (Exception e) {e.printstacktrace ();
} return Dsmap.get (did);
public void Removedatasource (String do) {if (dsmap==null) return;
Dsmap.remove (did); } private Combopooleddatasource Getnewdatasource (String did) throws exception{combopooleddatasource ds = new Combopool
Eddatasource (); Ds.setdriverclass ("xxx");//driver class String Jdbcurl = "jdbc:mysql://127.0.0.1 "//General IP Configuration in config file +": 3306 "+"/"+ Dbname_prefix + did +"? Useunicode=true&characterencoding=utf-8 ";
Ds.setjdbcurl (Jdbcurl);
Ds.setuser ("user");
Ds.setpassword ("password");
Ds.setminpoolsize (1);
Ds.setmaxpoolsize (800);
Ds.setmaxidletime (2000);
Ds.setacquireincrement (1);
Ds.setmaxstatements (0);
Ds.setinitialpoolsize (100);
Ds.setidleconnectiontestperiod (1800);
Ds.setacquireretryattempts (10);
Ds.setacquireretrydelay (1000);
Ds.setbreakafteracquirefailure (FALSE);
Ds.setcheckouttimeout (10000);
Ds.setpreferredtestquery ("Select FORMID from flow_form where 1 = 2");
Ds.settestconnectiononcheckout (FALSE);
return DS;
} public Connection getconnection () throws SQLException {return Getdatasource (). getconnection (); Public Connection getconnection (string arg0, String arg1) throws SQLException {return Getdatasource (). GetConnect
Ion (arg0, arg1); } public PrintWriter Getlogwriter () throws SQLException {return Getdatasource (). Getlogwriter ();
} public int getlogintimeout () throws SQLException {return Getdatasource (). Getlogintimeout ();
} public void Setlogwriter (PrintWriter arg0) throws SQLException {Getdatasource (). Setlogwriter (arg0);
} public void setLoginTimeout (int arg0) throws SQLException {Getdatasource (). setLoginTimeout (arg0); } public DataSource Getdatasource (String datasourcename) throws SQLException {try{if (datasourcename==null| |
Datasourcename.equals ("")) {return this.datasource;
}else{DataSource ds = Dsmap.get (datasourcename);
if (Ds!=null) return DS;
else return null; }}catch (Nosuchbeandefinitionexception ex) {throw new SQLException ("There is not the DataSource <name:" +datasource
Name+ "> in the Applicationcontext!");}}
public void Setdatasource (Combopooleddatasource dataSource) {this.datasource = DataSource;
} public Combopooleddatasource Getdatasource () throws sqlexception{String did = THREADHOLDER.GETSP (); DatasourCe ds = Getdatasource (did);
if (ds = = null) return null;
else return (Combopooleddatasource) DS;
} public DataSource Getdefaultdatasource () throws sqlexception{return DataSource;
} @Override public boolean iswrapperfor (Class<?> arg0) throws SQLException {//TODO auto-generated method stub
return false;
} @Override Public <T> T Unwrap (class<t> arg0) throws SQLException {//TODO auto-generated method stub
return null; }
}
Implementation principle:
Create a new Multiclientdatasource class (implement DataSource interface) to replace the original Combopooleddatasource injected DataSource, The essence of the Multiclientdatasource class is to use a map, with the company ID (did) as key,value as connection, to determine in the Getconnection method whether the did key already exists in the map, If not, create a new connection and add it to the map