`
log_cd
  • 浏览: 1098444 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

Spring3 Annotation + Hibernate3-jpa2.0 + CGLIB + 多数据源

阅读更多
一、定义一个测试用Entity。
@Entity
public class Person implements Serializable {
	private static final long serialVersionUID = 1L;

	@Id @GeneratedValue @Column(name = "id")
	private Integer id;

	@Column(name = "last_name")
	private String lastName;

	@Column(name = "first_name")
	private String firstName;

	public String getFirstName(){return firstName;}

	public void setFirstName(String firstName){this.firstName = firstName;}

	public String getLastName(){return lastName;}

	public void setLastName(String lastName){this.lastName = lastName;	}

	public Integer getId(){return id;}

	public void setId(Integer id){this.id = id;}
}

二、applicationContext.xml与META-INF/persistent.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:tx="http://www.springframework.org/schema/tx"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:aop="http://www.springframework.org/schema/aop"
 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/context
  http://www.springframework.org/schema/context/spring-context-3.0.xsd
  http://www.springframework.org/schema/aop
  http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

      <!--指定spring容器自动扫描的包:@Repository...-->
	<context:component-scan base-package="com.logcd.test,com.logcd.dao,com.logcd.service"/> 
      <!--使用CGLIB代理-->
	<aop:aspectj-autoproxy proxy-target-class="true"/>

	<bean
       class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>

	<bean id="ds1" 
	  class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
	  <property name="driverClassName" value="com.mysql.jdbc.Driver"/> 
	  <property name="url" value="jdbc:mysql://localhost:3306/springapp"/> 
	  <property name="username" value="root"/> 
	  <property name="password" value="root"/> 
	</bean> 

	<bean id="ds2" 
	  class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
	  <property name="driverClassName" value="com.mysql.jdbc.Driver"/> 
	  <property name="url" value="jdbc:mysql://localhost:3306/test"/> 
	  <property name="username" value="root"/> 
	  <property name="password" value="root"/> 
	</bean> 
      <!--动态选择数据源-->
	<bean id="dataSource" class="com.logcd.util.DynamicDataSource">
		<property name="targetDataSources">
			<map key-type="java.lang.String">
				<entry key="1" value-ref="ds1"/>
				<entry key="2" value-ref="ds2"/>
			</map>
		</property>
		<property name="defaultTargetDataSource" ref="ds1"/>
    </bean>

    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
        destroy-method="destroy">
        <property name="dataSource" ref="dataSource" />
        <property name="jpaVendorAdapter">
            <bean
				class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
				<property name="database" value="MYSQL"/>
				<property name="generateDdl" value="true"/>
				<property name="showSql" value="true"/>
			</bean>
        </property>
    </bean>
    
    <bean id="transactionManager" 
        class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="dataSource" ref="dataSource"/>
        <property name="entityManagerFactory"
            ref="entityManagerFactory"/>
    </bean>
    
    <tx:annotation-driven transaction-manager="transactionManager"/>

</beans>

<persistence xmlns="http://java.sun.com/xml/ns/persistence" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://java.sun.com/xml/ns/persistencehttp://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" 
version="1.0"> 

	<!--  local or global(JTA) transaction -->
	<persistence-unit name="SpringJpa" transaction-type="RESOURCE_LOCAL"/>

</persistence> 

三、在Spring 2.0.1中引入了AbstractRoutingDataSource, 该类充当了DataSource的路由中介, 能有在运行时, 根据某种key值来动态切换到真正的DataSource上, 同时对于不支持事务隔离级别的JTA事务来说, Spring还提供了另外一个类IsolationLevelDataSourceRouter来处理。IsolationLevelDataSourceRouter: 会根据当前Spring受管事务启用的隔离级别来选定合适的DataSource数据源。
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class DynamicDataSource extends AbstractRoutingDataSource {

	@Override
	protected Object determineCurrentLookupKey() {
		
		return DbContextHolder.getDbType();
		
	}

}

public class DbContextHolder {
	
	private static final ThreadLocal<Object> contextHolder = new ThreadLocal<Object>();
	
	public static void setDbType(Object dbType) {
		contextHolder.set(dbType);
	}
	
	public static String getDbType() {
		return (String) contextHolder.get();
	}
	
	public static void clearDbType() {
		contextHolder.remove();
	}  
	
}

四、数据访问Dao
import java.io.Serializable;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

@Repository
@Transactional
public class BaseDao<T>{

	@PersistenceContext
    protected EntityManager em; 

	public void persist(T t) {
		em.persist(t);
	}

	@Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
      public T save(T t) {
		return em.merge(t);
	}

	public void delete(T t) {
		em.remove(t);
	}

	@Transactional(readOnly = true, isolation=Isolation.READ_COMMITTED)
	public T find(Class<T> clazz, Serializable id) {
		return em.getReference(clazz, id);
	}
	
	@SuppressWarnings("unchecked")
	public List<T> find(String jpql) {
		return em.createQuery(jpql).getResultList();
	}
	
	
	@SuppressWarnings("unchecked")
	public List<T> find(String jpql, Object param) {
		return em.createQuery(jpql).setParameter(1, param).getResultList();
	}

	@SuppressWarnings("unchecked")
	public List<T> find(String jpql, Object[] param) {
		Query query = em.createQuery(jpql);
		for (int i = 1; i <= param.length; i++) {
			query.setParameter(i, param[i - 1]);
		}
		return query.getResultList();
	}

	public int findTotalCount(String jpql) {
		return ((Long) em.createQuery(jpql).getSingleResult()).intValue();
	}
	
}

五、测试
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import java.util.List;

import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.logcd.dao.BaseDao;
import com.logcd.entity.Person;
import com.logcd.util.DbContextHolder;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestBaseDao extends AbstractJUnit4SpringContextTests{

	@Autowired
    private BaseDao<Person> baseDao;

	@Test
	public void findPersonById(){
		List<Person> persons =
            baseDao.find("from Person a where a.id = ?", new Integer(1));
        assertNotNull(persons);
        assertEquals(persons.size(), 1);

        for(Person person: persons){
        	System.out.println(person.getLastName()+" "+person.getFirstName());
        }
	}
	
	@Test
	public void savePerson(){
		DbContextHolder.setDbType("2");

		Person  person = new Person();
		person.setFirstName("Bella");
		person.setLastName("Edward");
		person = baseDao.save(person);
		System.out.println(person.getId());
		
		DbContextHolder.clearDbType();

	}
	
	@Ignore
	public void deletePerson(){
		baseDao.delete(baseDao.find(Person.class, new Integer(7)));
	}
	
}

六、关于Spring-AOP: JDK代理和CGLIB代理
1、如果目标对象实现了接口,默认会采用JDK的动态代理机制实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现接口,必须使用CGLIB生成代理,spring会自动在CGLIB和JDK动态代理之间切换
4、如何强制使用CGLIB生成代理?
(1)添加CGLIB库,SPRING_HOME/lib/cglib/*.jar
(2)在spring的配置文件中加入:<aop:aspectj-autoproxy proxy-target-class="true"/>
5、JDK代理和CGLIB代理的区别?
(1)JDK代理只能对实现了接口的类生成代理,而不能针对类
(2)CGLIB是针对类实现代理的,主要对指定的类生成一个子类,并覆盖其中的方法,因为是继承,所以不能使用final来修饰类或方法
七、关于IsolationLevelDataSourceRouter
public class IsolationLevelDataSourceRouterextends AbstractRoutingDataSourceDataSource that routes to one of various target DataSources based on the current transaction isolation level. The target DataSources need to be configured with the isolation level name as key, as defined on the TransactionDefinition interface.

This is particularly useful in combination with JTA transaction management (typically through Spring's JtaTransactionManager). Standard JTA does not support transaction-specific isolation levels. Some JTA providers support isolation levels as a vendor-specific extension (e.g. WebLogic), which is the preferred way of addressing this. As alternative (e.g. on WebSphere), the target database can be represented through multiple JNDI DataSources, each configured with a different isolation level (for the entire DataSource). The present DataSource router allows to transparently switch to the appropriate DataSource based on the current transaction's isolation level.

The configuration can for example look like this, assuming that the target DataSources are defined as individual Spring beans with names "myRepeatableReadDataSource", "mySerializableDataSource" and "myDefaultDataSource":

 <bean id="dataSourceRouter" class="org.springframework.jdbc.datasource.lookup.IsolationLevelDataSourceRouter">
   <property name="targetDataSources">
     <map>
       <entry key="ISOLATION_REPEATABLE_READ" value-ref="myRepeatableReadDataSource"/>
       <entry key="ISOLATION_SERIALIZABLE" value-ref="mySerializableDataSource"/>
     </map>
   </property>
   <property name="defaultTargetDataSource" ref="myDefaultDataSource"/>
 </bean>
Alternatively, the keyed values can also be data source names, to be resolved through a DataSourceLookup: by default, JNDI names for a standard JNDI lookup. This allows for a single concise definition without the need for separate DataSource bean definitions.
 <bean id="dataSourceRouter" class="org.springframework.jdbc.datasource.lookup.IsolationLevelDataSourceRouter">
   <property name="targetDataSources">
     <map>
       <entry key="ISOLATION_REPEATABLE_READ" value="java:comp/env/jdbc/myrrds"/>
       <entry key="ISOLATION_SERIALIZABLE" value="java:comp/env/jdbc/myserds"/>
     </map>
   </property>
   <property name="defaultTargetDataSource" value="java:comp/env/jdbc/mydefds"/>
 </bean>
Note: If you are using this router in combination with Spring's JtaTransactionManager, don't forget to switch the "allowCustomIsolationLevels" flag to "true". (By default, JtaTransactionManager will only accept a default isolation level because of the lack of isolation level support in standard JTA itself.)
 <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
   <property name="allowCustomIsolationLevels" value="true"/>
 </bean>
分享到:
评论
7 楼 yuyujulin 2011-07-28  
楼主你这个好像还是JPA-1.0耶,
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistencehttp://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">

<!--  local or global(JTA) transaction -->
<persistence-unit name="SpringJpa" transaction-type="RESOURCE_LOCAL"/>

</persistence>
6 楼 weir2009 2011-05-20  
Caused by: org.springframework.beans.NotWritablePropertyException: Invalid property 'dataSource' of bean class [org.springframework.orm.jpa.LocalEntityManagerFactoryBean]: Bean property 'dataSource' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
	at org.springframework.beans.BeanWrapperImpl.setPropertyV

这是怎么回事?
5 楼 angellin0 2011-04-30  
LZ, 为什么我在用的时候发现entityManager只实例化了一次,当调用Service时是直接调用的存储,而没有去切换datasource.
4 楼 lshoo 2011-03-13  
很好的例子,多谢!
3 楼 naoda 2010-11-10  
刚好项目需要使用多数据源,感谢你的分享!
2 楼 naoda 2010-11-10  
刚好项目上用到了多数据源,感谢你的分享!
1 楼 niukai_2000 2010-11-10  
写的不错,赞一个

相关推荐

    springmvc搭建详解

    2. Hibernate 相关的 jar 包:hibernate3.jar、hibernate-jpa-2.0-api-1.0.1.Final.jar 等,用于数据库操作和对象关系映射。 3. 其他依赖:如 antlr、dom4j、javassist、jta 等,以及对应数据库驱动的 jar 包,例如 ...

    jpa规范下的shh2配置要点.docx

    在JPA(Java Persistence API)规范下,SHH2(Hibernate Search、Hibernate ORM 和 Hibernate Tools 的组合)的配置涉及多个方面,包括依赖库、Spring框架的配置以及持久化单元的设置。以下是一些关键点的详细说明:...

    MyEclipse 6 Java 开发中文教程第十章

    - **Spring ORM**:提供了与ORM技术(如Hibernate、JPA)集成的支持。 - **Spring Web**:为构建Web应用程序提供了支持。 ##### 10.1.2 MyEclipse的Spring开发功能简介 MyEclipse是一个强大的集成开发环境(IDE)...

    spring3.07

    `org.springframework.jdbc.core.JdbcTemplate` 提供了简单的 SQL 执行操作,而 `org.springframework.orm.hibernate3.HibernateTemplate` 和 `org.springframework.orm.jpa.EntityManagerFactoryBean` 分别为 ...

    Spring API

    2. Spring 2.0和 2.5的新特性 2.1. 简介 2.2. 控制反转(IoC)容器 2.2.1. 新的bean作用域 2.2.2. 更简单的XML配置 2.2.3. 可扩展的XML编写 2.2.4. Annotation(注解)驱动配置 2.2.5. 在classpath中自动搜索组件...

    传智播客 Spring 完全文档 笔记总结

    - **事务管理器**:配置事务管理器(TransactionManager),并指定数据源等信息。 - **事务规则**:定义事务规则,如哪些方法需要开启事务、事务的传播行为等。 ##### 2.3 Spring 中事务的相关属性 - **隔离级别**...

    Spring中文帮助文档

    12.2.5. 基于Hibernate3的原生API实现DAO 12.2.6. 编程式的事务划分 12.2.7. 声明式的事务划分 12.2.8. 事务管理策略 12.2.9. 容器资源 vs 本地资源 12.2.10. 在应用服务器中使用Hibernate的注意事项 12.3. ...

    详解Spring配置事务的五种方式

    1. **DataSource**:数据源,它是连接到数据库的桥梁,负责管理数据库连接。在使用Hibernate等ORM框架时,DataSource可能会被SessionFactory替代,因为SessionFactory是Hibernate的会话工厂,用于创建Session对象。 ...

    Spring事务配置[收集].pdf

    1. **DataSource**: 数据源是连接到数据库的桥梁,用于获取数据库连接。在Spring中,可以通过`org.springframework.jdbc.datasource.DriverManagerDataSource`或`org.apache.commons.dbcp.BasicDataSource`等类来...

    spring MVC搭建及配置详解

    你需要将这些版本的jar包添加到项目的类路径中,包括Spring的核心库spring.jar、Spring MVC库spring-webmvc.jar、日志库commons-logging.jar以及CGLIB库cglib-nodep-2.1_3.jar等。同时,为了集成Hibernate,还需要...

Global site tag (gtag.js) - Google Analytics