spring事务传播之NESTED
来源:互联网 发布:晨曦计价软件官网 编辑:程序博客网 时间:2024/05/21 10:09
下面是官方的解释
/** * Execute within a nested transaction if a current transaction exists, * behave like PROPAGATION_REQUIRED else. There is no analogous feature in EJB. * <p>Note: Actual creation of a nested transaction will only work on specific * transaction managers. Out of the box, this only applies to the JDBC * DataSourceTransactionManager when working on a JDBC 3.0 driver. * Some JTA providers might support nested transactions as well. * @see org.springframework.jdbc.datasource.DataSourceTransactionManager */NESTED(TransactionDefinition.PROPAGATION_NESTED);
如果事务存在则在一个嵌套的事务中执行,如果没有则像PROPAGATION_REQUIRED表现形式一样,支持嵌套事务的前提条件
*JDBC3+
* 使用DataSourceTransactionManager 事务管理器
实例
spring配置文件
<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd"> <!-- 配置数据源 c3p0 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="${jdbc.driver}" /> <property name="jdbcUrl" value="${jdbc.url}" /> <property name="user" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <!-- 请求超时时间 --> <property name="checkoutTimeout" value="30000" /> <!-- 每60秒检查所有连接池中的空闲连接。默认值: 0,不检查 --> <property name="idleConnectionTestPeriod" value="30" /> <!-- 连接数据库连接池最大空闲时间 --> <property name="maxIdleTime" value="30" /> <!-- 连接池初始化连接数 --> <property name="initialPoolSize" value="10" /> <property name="minPoolSize" value="10" /> <property name="maxPoolSize" value="20" /> <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。默认值: 3 --> <property name="acquireIncrement" value="5" /> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 开始注解方式事务 --> <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/></beans>
测试代码
package org.bear.bookstore.test.propagation.jdbc;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.stereotype.Repository;import org.springframework.transaction.annotation.Propagation;import org.springframework.transaction.annotation.Transactional;@Repositorypublic class Nested { @Autowired JdbcTemplate jdbcTemplate; @Transactional( propagation=Propagation.REQUIRED, rollbackFor={Exception.class} ) public void a(){ jdbcTemplate.execute("insert into custom(address,cusname,email,phone,sex) values('北京市,朝阳区,十里河村','xxx','xx@qq.com','15555555555','1')"); int x = 1/0; System.out.println(x); } @Transactional( propagation=Propagation.NESTED, rollbackFor={Exception.class} ) public void b(){ jdbcTemplate.execute("insert into custom(address,cusname,email,phone,sex) values('北京市,朝阳区,十里河村','xxx','xxx@qq.com','15555555555','0')"); int x = 1/0; System.out.println(x); }}
package org.bear.bookstore.test.propagation.jdbc;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.stereotype.Repository;import org.springframework.transaction.annotation.Propagation;import org.springframework.transaction.annotation.Transactional;@Repositorypublic class Nested2 { @Autowired Nested nested; @Autowired JdbcTemplate jdbcTemplate; @Transactional( propagation=Propagation.REQUIRED, rollbackFor={Exception.class} ) public void a(){ /** * 如果aa()抛出异常,b未出现异常,则a会回滚b的结果 */ aa(); try { /** * 调用b,捕获异常,异常不会冒泡,aa()执行成功 * 也就是nested的用法,在一个类中这么调用没有效果,如调用aaa() */ nested.b(); /** * 如果调用a则会出现如下异常, * org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:724) at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:504) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:292) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655) at org.bear.bookstore.test.propagation.jdbc.Nested2$$EnhancerBySpringCGLIB$$567ca65b.a(<generated>) at org.bear.bookstore.test.propagation.JdbcTransactionPropagationTest.NestedTest(JdbcTransactionPropagationTest.java:25) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75) at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86) at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) */ //nested.a(); } catch (Exception e) { e.printStackTrace(); } } @Transactional( propagation=Propagation.REQUIRED, rollbackFor={Exception.class} ) public void aa(){ jdbcTemplate.execute("insert into custom(address,cusname,email,phone,sex) values('北京市,朝阳区,十里河村','xxx','xxx@qq.com','15555555555','1')"); /*int x = 1/0; System.out.println(x);*/ } /** * 这样的结果是 * 如果bbb是propagation=Propagation.NESTED,则两个custom都保存成功 * 如果bbb是propagation=Propagation.REQUIRED,则两个custom都保存成功 */ @Transactional( propagation=Propagation.REQUIRED, rollbackFor={Exception.class} ) public void aaa(){ jdbcTemplate.execute("insert into custom(address,cusname,email,phone,sex) values('北京市,朝阳区,十里河村','xxx','xxx@qq.com','15555555555','1')"); try { bbb(); } catch (Exception e) { e.printStackTrace(); } } @Transactional( //propagation=Propagation.NESTED, propagation=Propagation.REQUIRED, rollbackFor={Exception.class} ) public void bbb(){ jdbcTemplate.execute("insert into custom(address,cusname,email,phone,sex) values('北京市,朝阳区,十里河村','xxx','xxx@qq.com','15555555555','1')"); int x = 1/0; System.out.println(x); }}
package org.bear.bookstore.test.propagation;import org.bear.bookstore.test.propagation.jdbc.Nested2;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.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration( locations={"file:src/test/resources/spring-app-jdbc.xml","file:src/test/resources/spring-jdbc.xml"} )public class JdbcTransactionPropagationTest { /** * 运行在datasourcemanager中 */ @Autowired Nested2 Nested; /** * PROPAGATION_NESTED * */ @Test public void NestedTest(){ Nested.a(); //Nested.aaa(); }}
实验分析
咱们看堆栈信息
Thread [main] (Suspended (breakpoint at line 186 in DataSourceTransactionManager)) DataSourceTransactionManager.doGetTransaction() line: 186 DataSourceTransactionManager(AbstractPlatformTransactionManager).getTransaction(TransactionDefinition) line: 337 TransactionInterceptor(TransactionAspectSupport).createTransactionIfNecessary(PlatformTransactionManager, TransactionAttribute, String) line: 447 TransactionInterceptor(TransactionAspectSupport).invokeWithinTransaction(Method, Class<?>, InvocationCallback) line: 277 TransactionInterceptor.invoke(MethodInvocation) line: 96 CglibAopProxy$CglibMethodInvocation(ReflectiveMethodInvocation).proceed() line: 179 CglibAopProxy$DynamicAdvisedInterceptor.intercept(Object, Method, Object[], MethodProxy) line: 655 Nested$$EnhancerBySpringCGLIB$$cb68a86.b() line: not available Nested2.a() line: 28 Nested2$$FastClassBySpringCGLIB$$7a769380.invoke(int, Object, Object[]) line: not available MethodProxy.invoke(Object, Object[]) line: 204 CglibAopProxy$CglibMethodInvocation.invokeJoinpoint() line: 720 CglibAopProxy$CglibMethodInvocation(ReflectiveMethodInvocation).proceed() line: 157 TransactionInterceptor$1.proceedWithInvocation() line: 99 TransactionInterceptor(TransactionAspectSupport).invokeWithinTransaction(Method, Class<?>, InvocationCallback) line: 282 TransactionInterceptor.invoke(MethodInvocation) line: 96 CglibAopProxy$CglibMethodInvocation(ReflectiveMethodInvocation).proceed() line: 179 CglibAopProxy$DynamicAdvisedInterceptor.intercept(Object, Method, Object[], MethodProxy) line: 655 Nested2$$EnhancerBySpringCGLIB$$d54acf0.a() line: not available JdbcTransactionPropagationTest.NestedTest() line: 25 NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method] NativeMethodAccessorImpl.invoke(Object, Object[]) line: not available DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: not available Method.invoke(Object, Object...) line: not available FrameworkMethod$1.runReflectiveCall() line: 50 FrameworkMethod$1(ReflectiveCallable).run() line: 12 FrameworkMethod.invokeExplosively(Object, Object...) line: 47 InvokeMethod.evaluate() line: 17 RunBeforeTestMethodCallbacks.evaluate() line: 75 RunAfterTestMethodCallbacks.evaluate() line: 86 SpringRepeat.evaluate() line: 84 SpringJUnit4ClassRunner(ParentRunner<T>).runLeaf(Statement, Description, RunNotifier) line: 325 SpringJUnit4ClassRunner.runChild(FrameworkMethod, RunNotifier) line: 252 SpringJUnit4ClassRunner.runChild(Object, RunNotifier) line: 94 ParentRunner$3.run() line: 290 ParentRunner$1.schedule(Runnable) line: 71 SpringJUnit4ClassRunner(ParentRunner<T>).runChildren(RunNotifier) line: 288 ParentRunner<T>.access$000(ParentRunner, RunNotifier) line: 58 ParentRunner$2.evaluate() line: 268 RunBeforeTestClassCallbacks.evaluate() line: 61 RunAfterTestClassCallbacks.evaluate() line: 70 SpringJUnit4ClassRunner(ParentRunner<T>).run(RunNotifier) line: 363 SpringJUnit4ClassRunner.run(RunNotifier) line: 191 JUnit4TestReference.run(TestExecution) line: 86 TestExecution.run(ITestReference[]) line: 38 RemoteTestRunner.runTests(String[], String, TestExecution) line: 459 RemoteTestRunner.runTests(TestExecution) line: 678 RemoteTestRunner.run() line: 382 RemoteTestRunner.main(String[]) line: 192
具体分析流程
重点日志打印信息2016-11-23 11:03:26.652 [main] DEBUG org.springframework.jdbc.core.JdbcTemplate at 430 - Executing SQL statement [insert into custom(address,cusname,email,phone,sex) values('北京市,朝阳区,十里河村','xxx','xxx@qq.com','15555555555','1')]2016-11-23 11:04:09.012 [main] DEBUG o.s.jdbc.datasource.DataSourceTransactionManager at 450 - Creating nested transaction with name [org.bear.bookstore.test.propagation.jdbc.Nested.b]2016-11-23 11:04:09.102 [main] DEBUG org.springframework.jdbc.core.JdbcTemplate at 430 - Executing SQL statement [insert into custom(address,cusname,email,phone,sex) values('北京市,朝阳区,十里河村','xxx','xxx@qq.com','15555555555','0')]2016-11-23 11:04:09.104 [main] DEBUG o.s.jdbc.datasource.DataSourceTransactionManager at 845 - Rolling back transaction to savepointjava.lang.ArithmeticException: / by zero at org.bear.bookstore.test.propagation.jdbc.Nested.b(Nested.java:30) at org.bear.bookstore.test.propagation.jdbc.Nested$$FastClassBySpringCGLIB$$c1e2caf2.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655) at org.bear.bookstore.test.propagation.jdbc.Nested$$EnhancerBySpringCGLIB$$cb68a86.b(<generated>) at org.bear.bookstore.test.propagation.jdbc.Nested2.a(Nested2.java:28) at org.bear.bookstore.test.propagation.jdbc.Nested2$$FastClassBySpringCGLIB$$7a769380.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655) at org.bear.bookstore.test.propagation.jdbc.Nested2$$EnhancerBySpringCGLIB$$d54acf0.a(<generated>) at org.bear.bookstore.test.propagation.JdbcTransactionPropagationTest.NestedTest(JdbcTransactionPropagationTest.java:25) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75) at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86) at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)2016-11-23 11:04:09.102 [main] DEBUG org.springframework.jdbc.core.JdbcTemplate at 430 - Executing SQL statement [insert into custom(address,cusname,email,phone,sex) values('北京市,朝阳区,十里河村','xxx','xxx@qq.com','15555555555','0')]2016-11-23 11:04:09.111 [main] DEBUG o.s.jdbc.datasource.DataSourceTransactionManager at 759 - Initiating transaction commit at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)2016-11-23 11:04:09.104 [main] DEBUG o.s.jdbc.datasource.DataSourceTransactionManager at 845 - Rolling back transaction to savepoint从堆栈信息和打印信息我们可以清楚的得到以下信息:测试类方法调用JdbcTransactionPropagationTest.NestedTest() line: 25CBLIB字节码增强我的service类Nested2$$EnhancerBySpringCGLIB$$d54acf0.a() line: not available事务拦截器拦截注解了事务的方法Nested2.a() line: 28 Nested2$$FastClassBySpringCGLIB$$7a769380.invoke(int, Object, Object[]) line: not available MethodProxy.invoke(Object, Object[]) line: 204 CglibAopProxy$CglibMethodInvocation.invokeJoinpoint() line: 720 CglibAopProxy$CglibMethodInvocation(ReflectiveMethodInvocation).proceed() line: 157 TransactionInterceptor$1.proceedWithInvocation() line: 99 TransactionInterceptor(TransactionAspectSupport).invokeWithinTransaction(Method, Class<?>, InvocationCallback) line: 282 TransactionInterceptor.invoke(MethodInvocation) line: 96 CglibAopProxy$CglibMethodInvocation(ReflectiveMethodInvocation).proceed() line: 179 CglibAopProxy$DynamicAdvisedInterceptor.intercept(Object, Method, Object[], MethodProxy) line: 655 发现调用了另一个service的声明了NESTED的方法,创建savepoint,走新的代理拦截流程Nested$$EnhancerBySpringCGLIB$$cb68a86.b() line: not available现在我们解释一些问题了为什么b的执行失败也不会影响aa方法的插入操作,因为b失败后事务,会回滚到我们保存的savepoint,(当然咱们必须捕获异常进行处理)然后继续往下执行,也就是执行a方法的其它流程为什么aa的执行失败会影响b,理由同上
总结
不闻不若闻之,闻之不若见之,见之不若知之,知之不若行之。
不断的学习,不断的交流,不断的实践
0 0
- spring事务传播之NESTED
- spring事务传播机制-REQUIRED嵌套NESTED
- Spring之事务传播属性
- 再析spring注解事务之事务传播
- spring之@Transactional事务传播性
- spring之@Transactional事务传播性 --Required
- Spring事务总结---传播级别以及REQUIRED_NEW及NESTED的使用场景(赞)
- Spring事务总结---传播级别以及REQUIRED_NEW及NESTED的使用场景(赞)
- 解惑spring事务传播特性之嵌套事务
- spring事务--传播策略
- Spring 事务传播属性
- spring事务传播特性
- Spring事务传播机制
- Spring事务传播机制
- Spring事务传播机制
- spring事务传播属性
- spring事务传播图解
- spring事务传播机制
- java:根据文件头来判断文件类型
- Go语言_函数学习篇
- 轮播
- 移动端页面禁用长按选中功能
- js操作cookie实现后台管理系统全站样式切换
- spring事务传播之NESTED
- oracle 函数操作
- iOS10 UI教程视图的几何形状
- xiebokejiushiweilejifen???
- Javascript
- golang学习记录之Cgo
- 2、编写程序,从键盘上输入两个电阻的值,求它们并联和串连的电阻值,输出结果保留两位小数。
- Java_容器_Collection_Iterator接口
- iOS面试题