Spring3 Annotation + Hibernate3-jpa2.0 + CGLIB + 多数据源(动态数据源)

本文主要是介绍Spring3 Annotation + Hibernate3-jpa2.0 + CGLIB + 多数据源(动态数据源),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、定义一个测试用Entity。 
Java代码   收藏代码
  1. @Entity  
  2. public class Person implements Serializable {  
  3.     private static final long serialVersionUID = 1L;  
  4.   
  5.     @Id @GeneratedValue @Column(name = "id")  
  6.     private Integer id;  
  7.   
  8.     @Column(name = "last_name")  
  9.     private String lastName;  
  10.   
  11.     @Column(name = "first_name")  
  12.     private String firstName;  
  13.   
  14.     public String getFirstName(){return firstName;}  
  15.   
  16.     public void setFirstName(String firstName){this.firstName = firstName;}  
  17.   
  18.     public String getLastName(){return lastName;}  
  19.   
  20.     public void setLastName(String lastName){this.lastName = lastName;  }  
  21.   
  22.     public Integer getId(){return id;}  
  23.   
  24.     public void setId(Integer id){this.id = id;}  
  25. }  

二、applicationContext.xml与META-INF/persistent.xml 
Xml代码   收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.  xmlns:tx="http://www.springframework.org/schema/tx"  
  5.  xmlns:context="http://www.springframework.org/schema/context"  
  6.  xmlns:aop="http://www.springframework.org/schema/aop"  
  7.  xsi:schemaLocation="http://www.springframework.org/schema/beans  
  8.   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
  9.   http://www.springframework.org/schema/tx  
  10.   http://www.springframework.org/schema/tx/spring-tx-3.0.xsd   
  11.   http://www.springframework.org/schema/context  
  12.   http://www.springframework.org/schema/context/spring-context-3.0.xsd  
  13.   http://www.springframework.org/schema/aop  
  14.   http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">  
  15.   
  16.       <!--指定spring容器自动扫描的包:@Repository...-->  
  17.     <context:component-scan base-package="com.logcd.test,com.logcd.dao,com.logcd.service"/>   
  18.       <!--使用CGLIB代理-->  
  19.     <aop:aspectj-autoproxy proxy-target-class="true"/>  
  20.   
  21.     <bean  
  22.        class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>  
  23.   
  24.     <bean id="ds1"   
  25.       class="org.springframework.jdbc.datasource.DriverManagerDataSource">   
  26.       <property name="driverClassName" value="com.mysql.jdbc.Driver"/>   
  27.       <property name="url" value="jdbc:mysql://localhost:3306/springapp"/>   
  28.       <property name="username" value="root"/>   
  29.       <property name="password" value="root"/>   
  30.     </bean>   
  31.   
  32.     <bean id="ds2"   
  33.       class="org.springframework.jdbc.datasource.DriverManagerDataSource">   
  34.       <property name="driverClassName" value="com.mysql.jdbc.Driver"/>   
  35.       <property name="url" value="jdbc:mysql://localhost:3306/test"/>   
  36.       <property name="username" value="root"/>   
  37.       <property name="password" value="root"/>   
  38.     </bean>   
  39.       <!--动态选择数据源-->  
  40.     <bean id="dataSource" class="com.logcd.util.DynamicDataSource">  
  41.         <property name="targetDataSources">  
  42.             <map key-type="java.lang.String">  
  43.                 <entry key="1" value-ref="ds1"/>  
  44.                 <entry key="2" value-ref="ds2"/>  
  45.             </map>  
  46.         </property>  
  47.         <property name="defaultTargetDataSource" ref="ds1"/>  
  48.     </bean>  
  49.   
  50.     <bean id="entityManagerFactory"  
  51.         class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"  
  52.         destroy-method="destroy">  
  53.         <property name="dataSource" ref="dataSource" />  
  54.         <property name="jpaVendorAdapter">  
  55.             <bean  
  56.                 class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">  
  57.                 <property name="database" value="MYSQL"/>  
  58.                 <property name="generateDdl" value="true"/>  
  59.                 <property name="showSql" value="true"/>  
  60.             </bean>  
  61.         </property>  
  62.     </bean>  
  63.       
  64.     <bean id="transactionManager"   
  65.         class="org.springframework.orm.jpa.JpaTransactionManager">  
  66.         <property name="dataSource" ref="dataSource"/>  
  67.         <property name="entityManagerFactory"  
  68.             ref="entityManagerFactory"/>  
  69.     </bean>  
  70.       
  71.     <tx:annotation-driven transaction-manager="transactionManager"/>  
  72.   
  73. </beans>  

Xml代码   收藏代码
  1. <persistence xmlns="http://java.sun.com/xml/ns/persistence"   
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
  3. xsi:schemaLocation="http://java.sun.com/xml/ns/persistencehttp://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"   
  4. version="1.0">   
  5.   
  6.     <!--  local or global(JTA) transaction -->  
  7.     <persistence-unit name="SpringJpa" transaction-type="RESOURCE_LOCAL"/>  
  8.   
  9. </persistence>   

三、在Spring 2.0.1中引入了AbstractRoutingDataSource, 该类充当了DataSource的路由中介, 能有在运行时, 根据某种key值来动态切换到真正的DataSource上, 同时对于不支持事务隔离级别的JTA事务来说, Spring还提供了另外一个类IsolationLevelDataSourceRouter来处理。IsolationLevelDataSourceRouter: 会根据当前Spring受管事务启用的隔离级别来选定合适的DataSource数据源。 
Java代码   收藏代码
  1. import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;  
  2.   
  3. public class DynamicDataSource extends AbstractRoutingDataSource {  
  4.   
  5.     @Override  
  6.     protected Object determineCurrentLookupKey() {  
  7.           
  8.         return DbContextHolder.getDbType();  
  9.           
  10.     }  
  11.   
  12. }  

Java代码   收藏代码
  1. public class DbContextHolder {  
  2.       
  3.     private static final ThreadLocal<Object> contextHolder = new ThreadLocal<Object>();  
  4.       
  5.     public static void setDbType(Object dbType) {  
  6.         contextHolder.set(dbType);  
  7.     }  
  8.       
  9.     public static String getDbType() {  
  10.         return (String) contextHolder.get();  
  11.     }  
  12.       
  13.     public static void clearDbType() {  
  14.         contextHolder.remove();  
  15.     }    
  16.       
  17. }  

四、数据访问Dao 
Java代码   收藏代码
  1. import java.io.Serializable;  
  2. import java.util.List;  
  3.   
  4. import javax.persistence.EntityManager;  
  5. import javax.persistence.PersistenceContext;  
  6. import javax.persistence.Query;  
  7.   
  8. import org.springframework.stereotype.Repository;  
  9. import org.springframework.transaction.annotation.Transactional;  
  10.   
  11. @Repository  
  12. @Transactional  
  13. public class BaseDao<T>{  
  14.   
  15.     @PersistenceContext  
  16.     protected EntityManager em;   
  17.   
  18.     public void persist(T t) {  
  19.         em.persist(t);  
  20.     }  
  21.   
  22.     @Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)  
  23.       public T save(T t) {  
  24.         return em.merge(t);  
  25.     }  
  26.   
  27.     public void delete(T t) {  
  28.         em.remove(t);  
  29.     }  
  30.   
  31.     @Transactional(readOnly = true, isolation=Isolation.READ_COMMITTED)  
  32.     public T find(Class<T> clazz, Serializable id) {  
  33.         return em.getReference(clazz, id);  
  34.     }  
  35.       
  36.     @SuppressWarnings("unchecked")  
  37.     public List<T> find(String jpql) {  
  38.         return em.createQuery(jpql).getResultList();  
  39.     }  
  40.       
  41.       
  42.     @SuppressWarnings("unchecked")  
  43.     public List<T> find(String jpql, Object param) {  
  44.         return em.createQuery(jpql).setParameter(1, param).getResultList();  
  45.     }  
  46.   
  47.     @SuppressWarnings("unchecked")  
  48.     public List<T> find(String jpql, Object[] param) {  
  49.         Query query = em.createQuery(jpql);  
  50.         for (int i = 1; i <= param.length; i++) {  
  51.             query.setParameter(i, param[i - 1]);  
  52.         }  
  53.         return query.getResultList();  
  54.     }  
  55.   
  56.     public int findTotalCount(String jpql) {  
  57.         return ((Long) em.createQuery(jpql).getSingleResult()).intValue();  
  58.     }  
  59.       
  60. }  

五、测试 
Java代码   收藏代码
  1. import static org.junit.Assert.assertEquals;  
  2. import static org.junit.Assert.assertNotNull;  
  3.   
  4. import java.util.List;  
  5.   
  6. import org.junit.Ignore;  
  7. import org.junit.Test;  
  8. import org.junit.runner.RunWith;  
  9. import org.springframework.beans.factory.annotation.Autowired;  
  10. import org.springframework.test.context.ContextConfiguration;  
  11. import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;  
  12. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  
  13.   
  14. import com.logcd.dao.BaseDao;  
  15. import com.logcd.entity.Person;  
  16. import com.logcd.util.DbContextHolder;  
  17.   
  18. @RunWith(SpringJUnit4ClassRunner.class)  
  19. @ContextConfiguration("classpath:applicationContext.xml")  
  20. public class TestBaseDao extends AbstractJUnit4SpringContextTests{  
  21.   
  22.     @Autowired  
  23.     private BaseDao<Person> baseDao;  
  24.   
  25.     @Test  
  26.     public void findPersonById(){  
  27.         List<Person> persons =  
  28.             baseDao.find("from Person a where a.id = ?"new Integer(1));  
  29.         assertNotNull(persons);  
  30.         assertEquals(persons.size(), 1);  
  31.   
  32.         for(Person person: persons){  
  33.             System.out.println(person.getLastName()+" "+person.getFirstName());  
  34.         }  
  35.     }  
  36.       
  37.     @Test  
  38.     public void savePerson(){  
  39.         DbContextHolder.setDbType("2");  
  40.   
  41.         Person  person = new Person();  
  42.         person.setFirstName("Bella");  
  43.         person.setLastName("Edward");  
  44.         person = baseDao.save(person);  
  45.         System.out.println(person.getId());  
  46.           
  47.         DbContextHolder.clearDbType();  
  48.   
  49.     }  
  50.       
  51.     @Ignore  
  52.     public void deletePerson(){  
  53.         baseDao.delete(baseDao.find(Person.classnew Integer(7)));  
  54.     }  
  55.       
  56. }  

六、关于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": 

Xml代码   收藏代码
  1. <bean id="dataSourceRouter" class="org.springframework.jdbc.datasource.lookup.IsolationLevelDataSourceRouter">  
  2.   <property name="targetDataSources">  
  3.     <map>  
  4.       <entry key="ISOLATION_REPEATABLE_READ" value-ref="myRepeatableReadDataSource"/>  
  5.       <entry key="ISOLATION_SERIALIZABLE" value-ref="mySerializableDataSource"/>  
  6.     </map>  
  7.   </property>  
  8.   <property name="defaultTargetDataSource" ref="myDefaultDataSource"/>  
  9. </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. 
Xml代码   收藏代码
  1. <bean id="dataSourceRouter" class="org.springframework.jdbc.datasource.lookup.IsolationLevelDataSourceRouter">  
  2.   <property name="targetDataSources">  
  3.     <map>  
  4.       <entry key="ISOLATION_REPEATABLE_READ" value="java:comp/env/jdbc/myrrds"/>  
  5.       <entry key="ISOLATION_SERIALIZABLE" value="java:comp/env/jdbc/myserds"/>  
  6.     </map>  
  7.   </property>  
  8.   <property name="defaultTargetDataSource" value="java:comp/env/jdbc/mydefds"/>  
  9. </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.) 
Xml代码   收藏代码
  1. <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">  
  2.   <property name="allowCustomIsolationLevels" value="true"/>  
  3. </bean>  

这篇关于Spring3 Annotation + Hibernate3-jpa2.0 + CGLIB + 多数据源(动态数据源)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1079763

相关文章

Spring Boot 整合 SSE的高级实践(Server-Sent Events)

《SpringBoot整合SSE的高级实践(Server-SentEvents)》SSE(Server-SentEvents)是一种基于HTTP协议的单向通信机制,允许服务器向浏览器持续发送实... 目录1、简述2、Spring Boot 中的SSE实现2.1 添加依赖2.2 实现后端接口2.3 配置超时时

Spring Boot读取配置文件的五种方式小结

《SpringBoot读取配置文件的五种方式小结》SpringBoot提供了灵活多样的方式来读取配置文件,这篇文章为大家介绍了5种常见的读取方式,文中的示例代码简洁易懂,大家可以根据自己的需要进... 目录1. 配置文件位置与加载顺序2. 读取配置文件的方式汇总方式一:使用 @Value 注解读取配置方式二

一文详解Java异常处理你都了解哪些知识

《一文详解Java异常处理你都了解哪些知识》:本文主要介绍Java异常处理的相关资料,包括异常的分类、捕获和处理异常的语法、常见的异常类型以及自定义异常的实现,文中通过代码介绍的非常详细,需要的朋... 目录前言一、什么是异常二、异常的分类2.1 受检异常2.2 非受检异常三、异常处理的语法3.1 try-

Java中的@SneakyThrows注解用法详解

《Java中的@SneakyThrows注解用法详解》:本文主要介绍Java中的@SneakyThrows注解用法的相关资料,Lombok的@SneakyThrows注解简化了Java方法中的异常... 目录前言一、@SneakyThrows 简介1.1 什么是 Lombok?二、@SneakyThrows

Java中字符串转时间与时间转字符串的操作详解

《Java中字符串转时间与时间转字符串的操作详解》Java的java.time包提供了强大的日期和时间处理功能,通过DateTimeFormatter可以轻松地在日期时间对象和字符串之间进行转换,下面... 目录一、字符串转时间(一)使用预定义格式(二)自定义格式二、时间转字符串(一)使用预定义格式(二)自

Spring 请求之传递 JSON 数据的操作方法

《Spring请求之传递JSON数据的操作方法》JSON就是一种数据格式,有自己的格式和语法,使用文本表示一个对象或数组的信息,因此JSON本质是字符串,主要负责在不同的语言中数据传递和交换,这... 目录jsON 概念JSON 语法JSON 的语法JSON 的两种结构JSON 字符串和 Java 对象互转

JAVA保证HashMap线程安全的几种方式

《JAVA保证HashMap线程安全的几种方式》HashMap是线程不安全的,这意味着如果多个线程并发地访问和修改同一个HashMap实例,可能会导致数据不一致和其他线程安全问题,本文主要介绍了JAV... 目录1. 使用 Collections.synchronizedMap2. 使用 Concurren

Java Response返回值的最佳处理方案

《JavaResponse返回值的最佳处理方案》在开发Web应用程序时,我们经常需要通过HTTP请求从服务器获取响应数据,这些数据可以是JSON、XML、甚至是文件,本篇文章将详细解析Java中处理... 目录摘要概述核心问题:关键技术点:源码解析示例 1:使用HttpURLConnection获取Resp

Java的栈与队列实现代码解析

《Java的栈与队列实现代码解析》栈是常见的线性数据结构,栈的特点是以先进后出的形式,后进先出,先进后出,分为栈底和栈顶,栈应用于内存的分配,表达式求值,存储临时的数据和方法的调用等,本文给大家介绍J... 目录栈的概念(Stack)栈的实现代码队列(Queue)模拟实现队列(双链表实现)循环队列(循环数组

Java中Switch Case多个条件处理方法举例

《Java中SwitchCase多个条件处理方法举例》Java中switch语句用于根据变量值执行不同代码块,适用于多个条件的处理,:本文主要介绍Java中SwitchCase多个条件处理的相... 目录前言基本语法处理多个条件示例1:合并相同代码的多个case示例2:通过字符串合并多个case进阶用法使用