前段时间有个项目,spring+hibernate 的框架,这个项目是数据库传输相关的,会配置好几个数据库,就考虑能否把数据库配置放在 一个表里,程序启动时加载,这样会减少配置文件,清晰明了。
简介
如果你的工程要操作多个数据库,而且都要集成到spring中,用spring 的配置文件配置是很常见的。配置多个xml然后import到主xml(applicationContext.xml),里面把datasource 和beanfactory ,扫描包等配置好即可,
不过动态加的话,就有所不同了。当然是先 百度/google一下了,发现有不少案例是 多数据源+动态切换,不过这和我们的程序还是有出入的.后来找到一个 动态加bean 的,类似:
DefaultListableBeanFactory dbf = (DefaultListableBeanFactory) appContext.getBeanFactory();
BeanDefinitionBuilder dataSourceBuider = BeanDefinitionBuilder.genericBeanDefinition(ComboPooledDataSource.class);
有了这个ioc的入口,那就简单些了,至少在定义bean方面是没问题的。
代码
文件一,beans.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" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.1.xsd">
</beans>
文件二,ThirdImplTest.java (启动spring动态加载数据源)
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.log4j.Logger;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class ThirdImplTest {
static Logger log = Logger.getLogger(TgdUserServiceThirdImplTest.class);
TgdUserServiceThirdImpl impl ;
@Before
public void beforeS() {
ConfigurableApplicationContext appContext = new ClassPathXmlApplicationContext("classpath:beans.xml");
appContext = (ConfigurableApplicationContext) tooper(appContext);
impl = (TgdUserServiceThirdImpl)appContext.getBean("tgdUserServiceThirdImpl");
}
/**
* 操作 代码注入
* @param dbf
* @param appContext
*/
private ApplicationContext tooper(ConfigurableApplicationContext appContext){
String driverClass = "com.mysql.jdbc.Driver";
String jdbcUrl = "jdbc:mysql://192.168.1.1:3306/xxx?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&pinGlobalTxToPhysicalConnection=true&autoReconnect=true&useOldAliasMetadataBehavior=true";
String user = "root";
String password = "xxxx";
DefaultListableBeanFactory dbf = (DefaultListableBeanFactory) appContext.getBeanFactory();
BeanDefinitionBuilder dataSourceBuider = BeanDefinitionBuilder .genericBeanDefinition(ComboPooledDataSource.class);
dataSourceBuider.addPropertyValue("driverClass", driverClass);
dataSourceBuider.addPropertyValue("jdbcUrl", jdbcUrl);
dataSourceBuider.addPropertyValue("user",user);
dataSourceBuider.addPropertyValue("password",password);
dataSourceBuider.addPropertyValue("acquireIncrement","5");
dataSourceBuider.addPropertyValue("initialPoolSize","3");
dataSourceBuider.addPropertyValue("minPoolSize","3");
dataSourceBuider.addPropertyValue("maxPoolSize","10");
dataSourceBuider.addPropertyValue("maxIdleTime","600");
dataSourceBuider.addPropertyValue("idleConnectionTestPeriod","3600");
dataSourceBuider.addPropertyValue("maxStatements","100");
dataSourceBuider.addPropertyValue("numHelperThreads","10");
dataSourceBuider.addPropertyValue("testConnectionOnCheckout",false);
dataSourceBuider.addPropertyValue("preferredTestQuery","SELECT 1 FROM DUAL");
dataSourceBuider.addPropertyValue("breakAfterAcquireFailure",false);
dataSourceBuider.addPropertyValue("acquireRetryAttempts",30);
dbf.registerBeanDefinition("third_dataSource", dataSourceBuider.getBeanDefinition());
// 配置 LocalSessionFactoryBean
//LocalSessionFactoryBean注册,注册时候在获取结果不再是它本身而是sessionFactory
BeanDefinitionBuilder llfb = BeanDefinitionBuilder .genericBeanDefinition(LocalSessionFactoryBean.class);
//这里的属性对应配置文件或者LocalSessionFactoryBean源码中的属性来,自己去看看就晓得
llfb.addPropertyValue("dataSource", (DataSource)appContext.getBean("third_dataSource"));
List<String> packagesToScanList = new ArrayList();
packagesToScanList.add("com.snm.third");
llfb.addPropertyValue("packagesToScan", packagesToScanList);
Properties p = new Properties();
p.setProperty("hibernate.hbm2ddl.auto","none");
p.setProperty("hibernate.dialect","org.hibernate.dialect.MySQL5Dialect");
p.setProperty("hibernate.show_sql","true");
p.setProperty("hibernate.form_sql","true");
p.setProperty("hibernate.connection.username",user);
p.setProperty("hibernate.connection.password",password);
p.setProperty("hibernate.connection.url",jdbcUrl);
p.setProperty("hibernate.default_batch_fetch_size","30");
p.setProperty("hibernate.cache.use_second_level_cache","false");
p.setProperty("hibernate.current_session_context_class","org.springframework.orm.hibernate4.SpringSessionContext");
// p.setProperty("hibernate.current_session_context_class","thread");
llfb.addPropertyValue("hibernateProperties",p);
dbf.registerBeanDefinition("third_sessionFactory", llfb.getBeanDefinition());
// 本来想看看集成spring 事务怎么搞的, 不过搞不定,这几行貌似没什么用
// construct an appropriate transaction manager
// DataSourceTransactionManager txManager = new DataSourceTransactionManager((DataSource)appContext.getBean("third_dataSource"));
// // configure the AnnotationTransactionAspect to use it; this must be done before executing any transactional methods
// AnnotationTransactionAspect.aspectOf().setTransactionManager(txManager);
AnnotationConfigApplicationContext annotationConfigApplicationContext =
new AnnotationConfigApplicationContext();
annotationConfigApplicationContext.setParent(appContext);
annotationConfigApplicationContext.scan("com.xxx.xxx");
annotationConfigApplicationContext.refresh();
return annotationConfigApplicationContext;
}
@Test
public void testgetAllList() throws Exception {
log.info(DJsonUtil.getJsonFromObect(impl.getAllList1(new HashMap(), null)));
}
}
文件三 TUserServiceThirdImpl
import java.util.List;
import java.util.Map;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.apache.util.Sort;
import com.snm.third.model.equpt.TgdUser;
@Service
public class TUserServiceThirdImpl{
@Autowired
private SessionFactory sessionFactory;
public List getAllList1(Map<String, String> params, Sort sorts) {
Session session = null;
List list = null;
try {
session = sessionFactory.openSession();
SQLQuery query = session.createSQLQuery("select * from tuser");
list = query.list();
} catch (Exception e) {
e.printStackTrace();
} finally {
session.close();
}
return list;
}
}
上面三个文件,即可以使用了.
其它
- 在web中使用
在加载sping 时自己创建个类来继承sping的listen,重写
public void contextInitialized(ServletContextEvent event) 即可
public class SpringListener extends ContextLoaderListener{
private static ApplicationContext context ;
public static ApplicationContext getContext(){
return context;
}
@Override
public void contextInitialized(ServletContextEvent event) {
System.out.print("init spring================");
super.contextInitialized(event);
WebApplicationContext w = WebApplicationContextUtils.getWebApplicationContext(event.getServletContext());
context = tooper((ConfigurableApplicationContext) w); //这里加载
}
问题
- 自动事务问题
不知道spring的aop怎么配置,即这行不知道怎么配置。
<tx:annotation-driven transaction-manager="transactionManager" />
所以@Transactional 的使用暂时还没有。。如果要多数据源的事务,只能 begin后rollback
数据源的相互引用
平时使用spring的bean,都是直接@Resource,@Autowire 引进来,但多数据源的相互引用不行,数据源是一个个加载的,如果加A的过程中,有B的Autowire,则会依赖报错 。spring cloud ?
貌似有spring搭建配置中心 的说法,不过还没了解过.