标签:用户 asa subclass array 运行 nstat finally rdp connect
Spring是当今广泛使用的框架,为Java核心堆栈带来了许多强大的功能和扩展。然而,大多数人倾向于使用这些功能,而不了解其潜在的机制。
由于现实生活中没有“魔法”,我们将在这一系列文章中深入研究与事务和数据库相关的一些Spring功能。
第一篇文章是处理着名的@Transactional注释,为开发者节省了管理低级别事务代码的负担。
第二篇文章可以在这里:
Spring @ PersistenceContext / @ PersistenceUnit解释
注意:以下代码分析使用Spring 3.0.5正式发布我们仅关注J2SE环境(无EJB)和JPA API进行数据库管理。然而,分析的代码是通用的,在一定程度上适用于其他情况(J2EE平台,特定供应商JPA API ...)
1
2
3
4
五
|
@Transactional (value = "myTransactionManager" , propagation = Propagation.REQUIRED) public void myMethod() { ... } |
@Transactional注释的value属性不是必需的。如果没有提到,Spring将默认查看在上下文中声明的名称为“ transactionManager ”(defaultConvention)的bean 。
1
2
3
|
< bean id = "transactionManager" class = "org.springframework.orm.jpa.JpaTransactionManager" > < property name = "entityManagerFactory" ref = "entityManagerFactory" /> </ bean > |
1
|
< tx:annotation-driven /> |
要使@Transactional注解工作,您应该声明<tx:annotation-driven>标签(tx是“ http://www.springframework.org/schema/tx ” 的命名空间的快捷方式)
在本章中,我们将看到如何在Spring上下文中处理<tx:annotation-driven>标签声明
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/** * Parses the ‘<code></code>‘ tag. Will * {@link AopNamespaceUtils#registerAutoProxyCreatorIfNecessary register an AutoProxyCreator} * with the container as necessary. */ public BeanDefinition parse(Element element, ParserContext parserContext) { String mode = element.getAttribute( "mode" ); if ( "aspectj" .equals(mode)) { // mode="aspectj" registerTransactionAspect(element, parserContext); } else { // mode="proxy" // DEFAULT MODE AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext); } return null ; } |
对于大多数用户,我们属于else块(mode =“proxy”),所以我们调用AopAutoProxyConfigurer .configureAutoProxyCreator()
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
private static class AopAutoProxyConfigurer { public static void configureAutoProxyCreator(Element element, ParserContext parserContext) { AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element); if (!parserContext.getRegistry().containsBeanDefinition(TRANSACTION_ADVISOR_BEAN_NAME)) { Object eleSource = parserContext.extractSource(element); // Create the TransactionAttributeSource definition. RootBeanDefinition sourceDef = new RootBeanDefinition(AnnotationTransactionAttributeSource. class ); sourceDef.setSource(eleSource); sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); // The bean AnnotationTransactionAttributeSource is created and registed dynamically here String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef); // Create the TransactionInterceptor definition. // Point A RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor. class ); interceptorDef.setSource(eleSource); interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); // Set the declared transaction manager in to the transactionInterceptor, when available registerTransactionManager(element, interceptorDef); interceptorDef.getPropertyValues().add( "transactionAttributeSource" , new RuntimeBeanReference(sourceName)); // The bean TransactionInterceptor is created and registed dynamically here String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef); // Create the TransactionAttributeSourceAdvisor definition. // This bean is an AOP definition RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor. class ); advisorDef.setSource(eleSource); advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); // Inject the bean AnnotationTransactionAttributeSource into the AOP definition // Point B advisorDef.getPropertyValues().add( "transactionAttributeSource" , new RuntimeBeanReference(sourceName)); // Definition of advice bean = TransactionInterceptor previously declared advisorDef.getPropertyValues().add( "adviceBeanName" , interceptorName); if (element.hasAttribute( "order" )) { advisorDef.getPropertyValues().add( "order" , element.getAttribute( "order" )); } // The bean BeanFactoryTransactionAttributeSourceAdvisor is created and registed dynamically here parserContext.getRegistry().registerBeanDefinition(TRANSACTION_ADVISOR_BEAN_NAME, advisorDef); CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource); compositeDef.addNestedComponent( new BeanComponentDefinition(sourceDef, sourceName)); compositeDef.addNestedComponent( new BeanComponentDefinition(interceptorDef, interceptorName)); compositeDef.addNestedComponent( new BeanComponentDefinition(advisorDef, TRANSACTION_ADVISOR_BEAN_NAME)); parserContext.registerComponent(compositeDef); } } // Retrieve the transactionManager attribute defined on when available // Example private static void registerTransactionManager(Element element, BeanDefinition def) { def.getPropertyValues().add( "transactionManagerBeanName" , TxNamespaceHandler.getTransactionManagerName(element)); } } |
事务拦截器类是在第19行创建的
然后在<tx:annotation-driven>中声明的事务管理器在Spring上下文中被搜索并附加到该事务拦截器第24行
最后,bean在第28行的Spring环境中注册
从 第32行到第47行,Spring声明一个 TransactionAttributeSourceAdvisor bean并将其注册到上下文中。
在本章中,我们将了解如何在运行时通过Spring解析@Transactional注释以检索与事务相关的属性
1
2
3
4
五
6
7
8
9
10
11
12
13
|
// Injected at Point B private TransactionAttributeSource transactionAttributeSource; // Define a pointcut here for AOP, injecting the transactionAttributeSource that was // set in AopAutoProxyConfigurer // see Point B private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() { @Override protected TransactionAttributeSource getTransactionAttributeSource() { return transactionAttributeSource; } }; |
这里Spring刚刚定义了一个poincut顾问。它由一个由TransactionAttributeSourcePointcut类处理的poincut组成。这里的transactionAttributeSource是在overriden getTransactionAttributeSource()方法中动态传递给匿名类的
1
2
3
4
五
6
7
8
9
10
11
12
13
|
abstract class org.springframework.transaction.interceptor.TransactionAttributeSourcePointcut // Determine whether a call on a particular method matches the poincut // If it matches then the advice bean will be called // The advice bean that has been registered for this pointcut is the // TransactionInterceptor class (see Point A) public boolean matches(Method method, Class targetClass) { TransactionAttributeSource tas = getTransactionAttributeSource(); // Call getTransactionAttribute of the injected transactionAttributeSoirce // (see Point C) return (tas == null || tas.getTransactionAttribute(method, targetClass) != null ); } |
这个抽象类只定义maches()方法的默认行为,以检查连接点是否与此poincut匹配
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
// Should be false in a context of J2SE private static final boolean ejb3Present = ClassUtils.isPresent( "javax.ejb.TransactionAttribute" , AnnotationTransactionAttributeSource. class .getClassLoader()); // Default constructor public AnnotationTransactionAttributeSource() { this ( true ); } // publicMethodsOnly = true because this bean has been registered dynamically // by AopAutoProxyConfigurer with no argument so the default constructor above applies // // ejb3Present = false public AnnotationTransactionAttributeSource( boolean publicMethodsOnly) { this .publicMethodsOnly = publicMethodsOnly; this .annotationParsers = new LinkedHashSet( 2 ); this .annotationParsers.add( new SpringTransactionAnnotationParser()); if (ejb3Present) { this .annotationParsers.add( new Ejb3TransactionAnnotationParser()); } } |
AnnotationTransactionAttributeSource的第二个构造函数将SpringTransactionAnnotationParser注册为@Transactional注释的默认解析器
C点D点
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
// Point C public TransactionAttribute getTransactionAttribute(Method method, Class targetClass) { // First, see if we have a cached value. Object cacheKey = getCacheKey(method, targetClass); Object cached = this .attributeCache.get(cacheKey); if (cached != null ) { .... .... // Not interesting code } else { // We need to work it out. // (see Point D below) TransactionAttribute txAtt = computeTransactionAttribute(method, targetClass); // Put it in the cache. if (txAtt == null ) { this .attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE); } else { if (logger.isDebugEnabled()) { logger.debug( "Adding transactional method ‘" + method.getName() + "‘ with attribute: " + txAtt); } this .attributeCache.put(cacheKey, txAtt); } return txAtt; } } // Point D private TransactionAttribute computeTransactionAttribute(Method method, Class targetClass) { // Don‘t allow no-public methods as required. // Here allowPublicMethodsOnly() will return true because we set the attribute // publicMethodOnly = true in the constructor of AnnotationTransactionAttribute if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) { return null ; } // Ignore CGLIB subclasses - introspect the actual user class. Class userClass = ClassUtils.getUserClass(targetClass); // The method may be on an interface, but we need attributes from the target class. // If the target class is null, the method will be unchanged. Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass); // If we are dealing with method with generic parameters, find the original method. specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod); // Find the @Transactional attributes of the method in the target class. // (see Point E) TransactionAttribute txAtt = findTransactionAttribute(specificMethod); if (txAtt != null ) { return txAtt; } ... // Not interesting code } |
抽象类的getTransactionAttribute()最终将工作委派给computeTransactionAttribute()方法。
首先它确定目标类(如果注释被放在接口方法上),然后调用方法findTransactionAttribute()
点E
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
|
// Point E protected TransactionAttribute findTransactionAttribute(Method method) { // See below return determineTransactionAttribute(method); } protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) { for (TransactionAnnotationParser annotationParser : this .annotationParsers) { // (see Point F) TransactionAttribute attr = annotationParser.parseTransactionAnnotation(ae); if (attr != null ) { return attr; } } return null ; } |
再次,真正的工作不是在这里完成的,而是委派给注释解析器类SpringTransactionAnnotationParser之前注册在AnnotationTransactionAttributeSource的构造函数
F点
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
38
39
40
41
|
// Point F public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) { Transactional ann = ae.getAnnotation(Transactional. class ); if (ann == null ) { for (Annotation metaAnn : ae.getAnnotations()) { // @Transactional annotation ann = metaAnn.annotationType().getAnnotation(Transactional. class ); if (ann != null ) { break ; } } } if (ann != null ) { //See below return parseTransactionAnnotation(ann); } else { return null ; } } public TransactionAttribute parseTransactionAnnotation(Transactional ann) { RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); rbta.setPropagationBehavior(ann.propagation().value()); rbta.setIsolationLevel(ann.isolation().value()); rbta.setTimeout(ann.timeout()); rbta.setReadOnly(ann.readOnly()); /* Set qualifier name in the case multiple transaction managers are used * bean id="myTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" * property name="entityManagerFactory" ref="myEntityManagerFactory" / * /bean * * @Transactional(value = "myTransactionManager") */ rbta.setQualifier(ann.value()); ArrayList rollBackRules = new ArrayList(); ... // Not interesting code return rbta; } |
解析器将检索@Transactional注释的所有属性,其中:
如果省略,则value属性默认为“transactionManager”。在处理多个数据库或多个数据源应用程序时,在Spring上下文中定义了多个transactionManager,所以该值对于帮助Spring选择正确的一个是重要的。
在本章中,我们将介绍Spring如何实现事务划分
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
// The real job is done here public Object invoke( final MethodInvocation invocation) throws Throwable { // Work out the target class: may be <code>null</code>. // The TransactionAttributeSource should be passed the target class // as well as the method, which may be from an interface. Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null ); // If the transaction attribute is null, the method is non-transactional. //Similar to Point C final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(invocation.getMethod(), targetClass); // (see Point G) final PlatformTransactionManager tm = determineTransactionManager(txAttr); final String joinpointIdentification = methodIdentification(invocation.getMethod(), targetClass); // The txAttr is not null but the transactionManager is NOT an instance // of CallbackPreferringPlatformTransactionManager so we still enter the if block if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) { // Standard transaction demarcation with getTransaction() and commit/rollback calls. // (see Point H) TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); Object retVal = null ; try { // This is an around advice: Invoke the next interceptor in the chain. // This will normally result in a target object being invoked. retVal = invocation.proceed(); } catch (Throwable ex) { // target invocation exception completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { cleanupTransactionInfo(txInfo); } // Commit after the method call returns // (see Point O) commitTransactionAfterReturning(txInfo); return retVal; } |
G点H点
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
//Point G protected PlatformTransactionManager determineTransactionManager(TransactionAttribute txAttr) { if ( this .transactionManager != null || this .beanFactory == null || txAttr == null ) { return this .transactionManager; } String qualifier = txAttr.getQualifier(); // Case when the transaction manager has been declared directly in the @Transactional annotation // Example @Transactional(value = "myTransactionManager") if (StringUtils.hasLength(qualifier)) { return TransactionAspectUtils.getTransactionManager( this .beanFactory, qualifier); } // Case when the transaction manager has been declared in the tx:annotation-driven tag // Example tx:annotation driven transaction-manager="myTransactionManager" else if ( this .transactionManagerBeanName != null ) { return this .beanFactory.getBean( this .transactionManagerBeanName, PlatformTransactionManager. class ); } ... // Not interesting code } // Point H protected TransactionInfo createTransactionIfNecessary(PlatformTransactionManager tm, TransactionAttribute txAttr, final String joinpointIdentification) { // If no name specified, apply method identification as transaction name. // This is the default case if (txAttr != null && txAttr.getName() == null ) { txAttr = new DelegatingTransactionAttribute(txAttr) { @Override public String getName() { return joinpointIdentification; } }; } TransactionStatus status = null ; if (txAttr != null ) { if (tm != null ) { // Call to the AbstractPlatFormTransactionManager to start a transaction // (see Point I) status = tm.getTransaction(txAttr); } else { if (logger.isDebugEnabled()) { logger.debug( "Skipping transactional joinpoint [" + joinpointIdentification + "] because no transaction manager has been configured" ); } } } return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status); } |
这个课程正在做两个主要任务:
点我
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
//Point I public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException { // Retrieve the transaction from JpaTransactionManager.doGetTransaction() // (see Point J) Object transaction = doGetTransaction(); // Cache debug flag to avoid repeated checks. boolean debugEnabled = logger.isDebugEnabled(); if (definition == null ) { // Use defaults if no transaction definition given. definition = new DefaultTransactionDefinition(); } if (isExistingTransaction(transaction)) { // Existing transaction found -> check propagation behavior to find out how to behave. return handleExistingTransaction(definition, transaction, debugEnabled); } ... // No existing transaction found -> check propagation behavior to find out how to proceed. if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) { throw new IllegalTransactionStateException( "No existing transaction found for transaction marked with propagation ‘mandatory‘" ); } // Our case else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) { SuspendedResourcesHolder suspendedResources = suspend( null ); if (debugEnabled) { logger.debug( "Creating new transaction with name [" + definition.getName() + "]: " + definition); } try { boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER); /* * Return a new DefaultTransactionStatus(transaction, * newTransaction = true, * newSynchronization = true, * definition.isReadOnly(),debugEnabled, * suspendedResources) * for a new transaction */ DefaultTransactionStatus status = newTransactionStatus( definition, transaction, true , newSynchronization, debugEnabled, suspendedResources); // Real job here, delegates call to JpaTransactionManager.doBegin() // (see Point K) doBegin(transaction, definition); // Set some synchronization flags to the TransactionSynchronizationManager thread local prepareSynchronization(status, definition); return status; } catch (RuntimeException ex) { resume( null , suspendedResources); throw ex; } catch (Error err) { resume( null , suspendedResources); throw err; } } else { // TransactionDefinition = PROPAGATION_SUPPORTS or PROPAGATION_NOT_SUPPORTED // or PROPAGATION_NEVER // Create "empty" transaction: no actual transaction, but potentially synchronization. boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS); return prepareTransactionStatus(definition, null , true , newSynchronization, debugEnabled, null ); } } |
该getTransaction()委托创作和交易本身的底层开始JpaTransactionManager接口。
我们可以看到Spring如何管理不同类型的传播行为。
J&Point K
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
//Point J protected Object doGetTransaction() { JpaTransactionObject txObject = new JpaTransactionObject(); txObject.setSavepointAllowed(isNestedTransactionAllowed()); // Try to retrieve an EntityManagerHolder from the thread local map of // TransactionSynchronizationManager using the EntityManagerFactory as search key // The EntityManagerFactory was injected in the JpaTransactionManager in the XML config file // // bean id="myTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" // property name="entityManagerFactory" ref="myEntityManagerFactory" // bean // // // this EntityManagerHolder might be null when called the first time EntityManagerHolder emHolder = (EntityManagerHolder) TransactionSynchronizationManager.getResource(getEntityManagerFactory()); if (emHolder != null ) { if (logger.isDebugEnabled()) { logger.debug( "Found thread-bound EntityManager [" + emHolder.getEntityManager() + "] for JPA transaction" ); } // attach the EntityManagerHolder to the JpaTransactionObject // the flag false is set to the property newEntityManagerHolder txObject.setEntityManagerHolder(emHolder, false ); } // The datasource is injected directly into the JpaTransactionManager // after bean initialization (afterPropertySet()) // by inspecting the injected EntityManagerFactory // // bean id="myEntityManagerFactory" // class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" // property name="dataSource" ref="myDataSource" // property name="persistenceUnitName" value="myPersistenceUnit" // bean // // // this test always evaluates to true if (getDataSource() != null ) { ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(getDataSource()); // attach a connectionHolder to the JpaTransactionObject (to start JDBC transaction probably) txObject.setConnectionHolder(conHolder); } return txObject; } //Point K protected void doBegin(Object transaction, TransactionDefinition definition) { JpaTransactionObject txObject = (JpaTransactionObject) transaction; ... try { // The EntityManagerHolder can be null if not registered already in the // thread local map of TransactionSynchronizationManager if (txObject.getEntityManagerHolder() == null || txObject.getEntityManagerHolder().isSynchronizedWithTransaction()) { // Create a new EntityManager from the EntityManagerFactory EntityManager newEm = createEntityManagerForTransaction(); if (logger.isDebugEnabled()) { logger.debug( "Opened new EntityManager [" + newEm + "] for JPA transaction" ); } // attach the EntityManagerHolder to the JpaTransactionObject // newEntityManagerHolder = true // because the EntityManager has just been created from scratch txObject.setEntityManagerHolder( new EntityManagerHolder(newEm), true ); } EntityManager em = txObject.getEntityManagerHolder().getEntityManager(); final int timeoutToUse = determineTimeout(definition); /* Delegate to JpaDialect for actual transaction begin, passing the EntityManager * * META-INF|persistence.xml * * persistence-unit name="myPersistenceUnit" transaction-type="RESOURCE_LOCAL" * provider * org.hibernate.ejb.HibernatePersistence * provider * properties * property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect" * ... */ // (see Point L for HibernateJpaDialect) Object transactionData = getJpaDialect().beginTransaction(em, new DelegatingTransactionDefinition(definition) { @Override public int getTimeout() { return timeoutToUse; } }); // Set transaction data to the JpaTransactionObject txObject.setTransactionData(transactionData); // Register transaction timeout. if (timeoutToUse != TransactionDefinition.TIMEOUT_DEFAULT) { txObject.getEntityManagerHolder().setTimeoutInSeconds(timeoutToUse); } // Register the JPA EntityManager‘s JDBC Connection for the DataSource, if set. if (getDataSource() != null ) { // Retrieve the underlying JDBC connection by calling the JPA Dialect class ConnectionHandle conHandle = getJpaDialect().getJdbcConnection(em, definition.isReadOnly()); if (conHandle != null ) { ConnectionHolder conHolder = new ConnectionHolder(conHandle); if (timeoutToUse != TransactionDefinition.TIMEOUT_DEFAULT) { conHolder.setTimeoutInSeconds(timeoutToUse); } if (logger.isDebugEnabled()) { logger.debug( "Exposing JPA transaction as JDBC transaction [" + conHolder.getConnectionHandle() + "]" ); } // Set the JDBC connection to the current Threadlocal resources map, the // datasource being the key TransactionSynchronizationManager.bindResource(getDataSource(), conHolder); // Set JDBC connection holder to the JpaTransactionObject txObject.setConnectionHolder(conHolder); } else { if (logger.isDebugEnabled()) { logger.debug( "Not exposing JPA transaction [" + em + "] as JDBC transaction because JpaDialect [" + getJpaDialect() + "] does not support JDBC Connection retrieval" ); } } } // If the EntityManager has been created from scratch (see Point L) if (txObject.isNewEntityManagerHolder()) { // register the EntityManagerHolder to the current Threadlocal resources map, the EntityManagerFactory being the key TransactionSynchronizationManager.bindResource( getEntityManagerFactory(), txObject.getEntityManagerHolder()); } txObject.getEntityManagerHolder().setSynchronizedWithTransaction( true ); } catch (TransactionException ex) { closeEntityManagerAfterFailedBegin(txObject); throw ex; } catch (Exception ex) { closeEntityManagerAfterFailedBegin(txObject); throw new CannotCreateTransactionException( "Could not open JPA EntityManager for transaction" , ex); } } |
大部分重要工作都是在这个班上完成的。
点J:doGetTransaction()
点K:doBegin()
点L
1
2
3
4
五
6
7
8
9
10
11
12
13
|
// Point L public Object beginTransaction(EntityManager entityManager, TransactionDefinition definition) throws PersistenceException, SQLException, TransactionException { if (definition.getTimeout() != TransactionDefinition.TIMEOUT_DEFAULT) { getSession(entityManager).getTransaction().setTimeout(definition.getTimeout()); } // (see Point M) super .beginTransaction(entityManager, definition); // (see Point N) return prepareTransaction(entityManager, definition.isReadOnly(), definition.getName()); } |
我们来看看HibernateJpaDialect是默认的Jpa方言。我们可以看到,这个类正在调用超类DefaultJpaDialect来启动事务(第9行)
然后调用内部方法prepareTransaction() (第12行)
点M
1
2
3
4
五
6
7
8
9
10
11
12
|
// Point M public Object beginTransaction(EntityManager entityManager, TransactionDefinition definition) throws PersistenceException, SQLException, TransactionException { if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) { throw new InvalidIsolationLevelException( "Standard JPA does not support custom isolation levels - " + "use a special JpaDialect for your JPA implementation" ); } entityManager.getTransaction().begin(); return null ; } |
交易由实体经理开始。我们可以清楚地看到,只有默认的ISOLATION级别才被vanilla HibernateJpaDialect支持。任何尝试将隔离级别设置为其他ISOLATION_DEFAULT将触发异常的其他级别。
N点
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
//Point N public Object prepareTransaction(EntityManager entityManager, boolean readOnly, String name) throws PersistenceException { Session session = getSession(entityManager); FlushMode flushMode = session.getFlushMode(); FlushMode previousFlushMode = null ; if (readOnly) { // We should suppress flushing for a read-only transaction. session.setFlushMode(FlushMode.MANUAL); previousFlushMode = flushMode; } else { // We need AUTO or COMMIT for a non-read-only transaction. if (flushMode.lessThan(FlushMode.COMMIT)) { session.setFlushMode(FlushMode.AUTO); previousFlushMode = flushMode; } } return new SessionTransactionData(session, previousFlushMode); } |
该prepareTransaction()方法设置和保存以前的刷新模式,什么更多的,是...
点O
1
2
3
4
五
6
7
8
9
10
11
|
// Point O protected void commitTransactionAfterReturning(TransactionInfo txInfo) { if (txInfo != null && txInfo.hasTransaction()) { if (logger.isTraceEnabled()) { logger.trace( "Completing transaction for [" + txInfo.getJoinpointIdentification() + "]" ); } // Delegate the commit call to the underlying TransactioManager // (see Point P) txInfo.getTransactionManager().commit(txInfo.getTransactionStatus()); } } |
该方法只是将事务提交委托给事务管理器
点P
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
38
|
// Point P public final void commit(TransactionStatus status) throws TransactionException { if (status.isCompleted()) { throw new IllegalTransactionStateException(Transaction is already completed - do not call commit or rollback more than once per transaction"); } ... // Not interesting code processCommit(defStatus); // See below } private void processCommit(DefaultTransactionStatus status) throws TransactionException { try { boolean beforeCompletionInvoked = false ; try { // Commit pre-processing, not always implemented by the actual TransactionManager prepareForCommit(status); triggerBeforeCommit(status); triggerBeforeCompletion(status); … // Delegate the real commit to the actual TransactionManager // (see Point Q) doCommit(status); } ... try { // Commit post-processing, not always implemented by the actual TransactionManager triggerAfterCommit(status); } finally { triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED); } } finally { // (see Point M) cleanupAfterCompletion(status); } ... } |
再次,除了调用一些触发代码来准备提交之外,提交的真正工作被委托给方法doCommit()
提交完成之后,调用cleanupAfterCompletion()以在必要时清除TransactionSynchronizationManager ThreadLocal映射
点Q
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
//Point Q protected void doCommit(DefaultTransactionStatus status) { JpaTransactionObject txObject = (JpaTransactionObject) status.getTransaction(); if (status.isDebug()) { logger.debug( "Committing JPA transaction on EntityManager [" + txObject.getEntityManagerHolder().getEntityManager() + "]" ); } try { // The real commit is done here ! EntityTransaction tx = txObject.getEntityManagerHolder().getEntityManager().getTransaction(); tx.commit(); } catch (RollbackException ex) { if (ex.getCause() instanceof RuntimeException) { DataAccessException dex = getJpaDialect(). translateExceptionIfPossible((RuntimeException) ex.getCause()); if (dex != null ) { throw dex; } } throw new TransactionSystemException( "Could not commit JPA transaction" , ex); } catch (RuntimeException ex) { // Assumably failed to flush changes to database. throw DataAccessUtils.translateIfNecessary(ex, getJpaDialect()); } } |
再次,提交是对getEntityManager()。getTransaction()。commit()的简单调用,没有任何魔术。
点M
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
|
// Point M private void cleanupAfterCompletion(DefaultTransactionStatus status) { status.setCompleted(); if (status.isNewSynchronization()) { TransactionSynchronizationManager.clear(); } if (status.isNewTransaction()) { // (see Point N) doCleanupAfterCompletion(status.getTransaction()); } if (status.getSuspendedResources() != null ) { if (status.isDebug()) { logger.debug( "Resuming suspended transaction after completion of inner transaction" ); } resume(status.getTransaction(), (SuspendedResourcesHolder) status.getSuspendedResources()); } } |
只是间接的代码,真正的工作是在doCleanupAfterCompletion()
N点
1
2
3
4
五
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
|
// Point N protected void doCleanupAfterCompletion(Object transaction) { JpaTransactionObject txObject = (JpaTransactionObject) transaction; // Remove the entity manager holder from the thread. if (txObject.isNewEntityManagerHolder()) { TransactionSynchronizationManager.unbindResource(getEntityManagerFactory()); } txObject.getEntityManagerHolder().clear(); // Remove the JDBC connection holder from the thread, if exposed. if (txObject.hasConnectionHolder()) { TransactionSynchronizationManager.unbindResource(getDataSource()); try { getJpaDialect().releaseJdbcConnection( txObject.getConnectionHolder().getConnectionHandle(), txObject.getEntityManagerHolder().getEntityManager()); } catch (Exception ex) { // Just log it, to keep a transaction-related exception. logger.error( "Could not close JDBC connection after transaction" , ex); } } getJpaDialect().cleanupTransaction(txObject.getTransactionData()); // Remove the entity manager holder from the thread. if (txObject.isNewEntityManagerHolder()) { EntityManager em = txObject.getEntityManagerHolder().getEntityManager(); if (logger.isDebugEnabled()) { logger.debug( "Closing JPA EntityManager [" + em + "] after transaction" ); } EntityManagerFactoryUtils.closeEntityManager(em); } else { logger.debug( "Not closing pre-bound JPA EntityManager after transaction" ); } } |
这里有很多有趣的代码片段:
在挖掘@Transactional的Spring代码之后,我们可以说:
@Transactional管理的 伪代码:
标签:用户 asa subclass array 运行 nstat finally rdp connect
原文地址:http://www.cnblogs.com/LightChan/p/7456185.html