Spring的学习(四、Spring事务管理)

摘要:
所有这些属性都提供了事务应用的方法和描述策略。1.PlatformTransactionManagerPlatformTransactionManager接口是Spring提供的平台事务管理器,它提供三种事务操作方法来获取事务状态信息。在项目中通过XML配置事务详细信息,并通过事务管理器的getTransaction()方法获取事务状态TransactionStatus。

Spring事务管理的三个核心接口

Spring的事务管理是基于AOP实现的,而AOP是以方法为单位的。

Spring的事务属性分别为传播行为、隔离级别、只读和超时属性。所有这些属性提供了事务应用的方法和描述策略。

事务管理的三个核心接口:PlatformTransactionManager、TransactionDefinition、TransactionStatus。

1. PlatformTransactionManager

PlatformTransactionManager接口是Spring提供的平台事务管理器,用于管理事务。该接口中提供了三个事务操作方法,具体如下:

(1)TransactionStatus getTransaction(TransactionDefinition definition):用于获取事务状态信息。

(2)void commit(TransactionStatus status):用于提交事务。

(3)void rollback(TransactionStatus status):用于回滚事务。

在项目中通过XML配置事务的详细信息,Spring将这些信息封装到对象TransactionDefinition中,通过事务管理器的getTransaction()方法获得事务的状态TransactionStatus,就可以对事务进行下一步的操作。

2. TransactionDefinition

TransactionDefinition接口是事务定义(描述)对象,提供事务相关信息获取的方法,包括5个操作,具体如下:

(1)String getName():获取事务对象名称。

(2)int getIsolationLevel():获取事务的隔离级别。

(3)int getPropagationBehavior():获取事务的传播行为。

(4)int getTimeout():获取事务的超时时间。

(5)boolean isReadOnly():获取事务是否只读。

需要注意:事务传播行为的概念,事务的传播行为是指在同一个方法中,不同操作前后所使用的事务。

在事务管理过程中,传播行为可以控制是否需要创建事务以及如何创建事务,通常情况下,数据的查询不会影响原数据的改变,所以不需要进行事务管理,而对于数据的增加、修改、删除等操作,必须进行事务管理,如果没有指定事务的传播行为,默认传播行为是required。

传播行为的种类
属性名称描述
PROPAGATION_REQUIREDrequired支持当前事务。如果A方法已经在事务中,B将直接使用。如果没有将创建新事务。
PROPAGATION_SUPPORTSsupports支持当前事务。如果A方法已经在事务中,B将直接使用。如果没有将以非事务状态执行。
PROPAGATION_MANDATORYmandatory支持当前事务。如果A方法没有事务,将抛异常。
PROPAGATION_REQUIRES_NEWrequires_new将创建新的事务,如果A方法已经在事务中,将A事务挂起。
PROPAGATION_NOT_SUPPORTEDnot_supported不支持当前事务,总是以非事务状态执行。如果A方法已经在事务中,将挂起。
PROPAGATION_NEVERnever不支持当前事务,如果A方法在事务中,将抛异常。
PROPAGATION_NESTEDnested嵌套事务,底层将使用Savepoint形成嵌套事务。

3. TransactionStatus

TransactionStatus接口是事务的状态,描述了某一时间点上事务的状态信息,包含6个操作,具体如下:

(1)void flush():刷新事务。

(2)boolean hasSavepoint():获取是否存在保存点。

(3)boolean isCompleted():获取事务是否完成。

(4)boolean isNewTransaction():获取是否是新事务。

(5)boolean isRollbackOnly():获取是否回滚。

(6)void setRollbackOnly():设置事务回滚。

 

TransactionProxyFactoryBean实现声明式事务管理

Spring的事务管理分为两种方式,声明式事务管理和编程式事务管理。

编程式事务管理

使用事务模板TransactionTemplate手动地管理事务,在实际开发中一般不使用,这里了解即可。

声明式事务管理

是Spring最原始的事务管理方式,我们需要在配置文件中定义数据源和事务管理器,然后把事务管理器注入到TransactionProxyFactoryBean中,设置目标类和事务的相关属性,使用TransactionProxyFactoryBean生成代理,它的优势在于代码中无须关注事务逻辑,而是交给Spring容器进行事务控制。

数据库:表名:acount 字段:id name money 存两组值:1,jack,1000/2,rose,1000。

c3p0-db.properties

jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql:///spring
jdbc.user=root
jdbc.password=root

applicationContext.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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd"
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

        <!--加载properties文件 -->
        <context:property-placeholder location="classpath:c3p0-db.properties"/>
        <!--配置数据源,读取properties文件信息 -->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="${jdbc.driverClass}"></property>
            <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
            <property name="user" value="${jdbc.user}"></property>
            <property name="password" value="${jdbc.password}"></property>
        </bean>
        <!--配置JDBC模板 -->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="jdbcTemplate" ref="dataSource"></property>
        </bean>
        <!--配置dao -->
        <bean id="accountDao" class="cn.tm.dao.impl.AccountDaoImpl">
            <property name="jdbcTemplate" ref="jdbcTemplate"></property>
        </bean>
        <!--配置service -->
        <bean id="accountService" class="cn.tm.dao.impl.AccountServiceImpl">
            <property name="accountDao" ref="accountDao"></property>
        </bean>
        <!--事务管理器,依赖于数据源 -->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
        <!--生成代理类,让代理管理事务,依赖于事务管理器 -->
        <bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
            <!--提供事务管理器 -->
            <property name="transactionManager" ref="transactionManager"></property>
            <!--目标类 -->
            <property name="target" ref="accountService"></property>
            <!--提供接口 -->
            <property name="proxyInterfaces" value="cn.tm.service.AccountService"></property>
            <!--事务的详情配置,给TransactionDefinition进行赋值 -->
            <property name="transactionAttributes">
                <props>
                    <!--key属性用来配置对目标内的哪些方法进行增强,*代表所有方法,如果是save*,表示以save开头的方法 -->
                    <!--text文本按照固定的格式编写事务的详情及TransactionDefinition的内容,例如传播行为、隔离界别等,值之间用逗号隔开 -->
                    <prop key="*">PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ</prop>
                </props>
            </property>
        </bean>
</beans>

AcountDao.java+AccountDaoImpl.java

package cn.tm.dao;
public interface AccountDao{
    //汇款
    public void out(String outUser,int money);
    //收款
    public void in(String inUser,int money);
}

package cn.tm.dao.impl;
public class AccountDaoImpl implements AccountDao{
    private JdbcTemplate jdbcTemplate;
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate){
        this.jdbcTemplate = jdbcTemplate;
    }
    //汇款的实现方法
    public void out(String outUser, int money) {
        this.jdbcTemplate.update("update account set money = money-?"+"where name=?",money,outUser);
    }
    //收款的实现方法
    public void in(String inUser, int money) {
        this.jdbcTemplate.update("update account set money = money+?"+"where name=?",money,inUser);
    }
}

AccountService.java+AccountServiceImpl.java

package cn.tm.service;
public interface AccountService{
    //转账方法
    public void transfer(String outUser,String inUser,int money);
}

package cn.tm.service.impl;
public class AccountServiceImpl implements AccountService{
    private AccountDao accountDao;
    public void setAccountDao(AccountDao accountDao){
        this.accountDao = accountDao;
    }
    @Override
    public void transfer(String outUser, String inUser, int money) {
        this.accountDao.out(outUser,money);
        this.accountDao.in(inUser,money);
    }
}

测试类

public class Test{
    public static void main(String[] args) {
        //xmlPath为applicationContext.xml文件的路径
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
        AccountService accountService = (AccountService)applicationContext.getBean("accountServiceProxy");
        //从jack的账户转100到rose的账户上
        accountService.transfer("jack","rose",100);
        System.out.println("ok");
    }
}

效果:

jack剩余900元,rose剩余1100元。如果转账的代码有问题,比如出现1/0这种情况,则两人钱仍然是1000元。

Spring AOP XML方式

上面的TransactionProxyFactoryBean实现声明式事务管理缺点是配置文件过于臃肿、难以阅读。因此,Spring提供了基于tx/AOP配置的声明式事务管理方式,也是实际开发中最常用的一种方式。其他代码同上,只修改了applicationContext.xml和测试类的代码。

applicationContext.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:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/cache" xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"
       http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/aop/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

        <!--加载properties文件 -->
        <context:property-placeholder location="classpath:c3p0-db.properties"/>
        <!--配置数据源,读取properties文件信息 -->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="${jdbc.driverClass}"></property>
            <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
            <property name="user" value="${jdbc.user}"></property>
            <property name="password" value="${jdbc.password}"></property>
        </bean>
        <!--配置JDBC模板 -->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="jdbcTemplate" ref="dataSource"></property>
        </bean>
        <!--配置dao -->
        <bean id="accountDao" class="cn.tm.dao.impl.AccountDaoImpl">
            <property name="jdbcTemplate" ref="jdbcTemplate"></property>
        </bean>
        <!--配置service -->
        <bean id="accountService" class="cn.tm.dao.impl.AccountServiceImpl">
            <property name="accountDao" ref="accountDao"></property>
        </bean>
        <!--事务管理器,依赖于数据源 -->
        <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
        <!--编写通知:对事物进行增强(通知),需要编写对切入点和具体执行事务细节 -->
        <tx:advice id="txAdvice" transaction-manager="txManager">
            <tx:attributes>
                <!-- tx:method给切入点方法添加事务详情 name:方法名称,*表示任意方法名称,save* 即是以save开头  -->
                <!-- propagation:设置传播行为  isolation:隔离级别  read-only:是否只读  -->
                <tx:method name="*" propagation="REQUIRED" isolation="DEFAULT" read-only="false"/>
            </tx:attributes>
        </tx:advice>
        <!--aop编写,让Spring自动对目标生成代理,需要使用AspectJ的表达式 -->
        <aop:config>
            <!--切入点 -->
            <aop:pointcut expression="execution(* cn.tm.service.*.*(..))" id="txPointCut"/>
            <!--切面:将切入点与通知整合 -->
            <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
        </aop:config>
</beans>

测试类:(getBean内的内容做了修改)

public class Test{
    public static void main(String[] args) {
        //xmlPath为applicationContext.xml文件的路径
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
        AccountService accountService = (AccountService)applicationContext.getBean("accountService");
        //从jack的账户转100到rose的账户上
        accountService.transfer("jack","rose",100);
        System.out.println("ok");
    }
}

Spring AOP Annotation方式

 

Spring的声明式事务管理还可以通过Annotation注解的方式,这种方式很简单。我们需要做的只有两步:Spring容器中注册驱动,在需要使用事务的业务类或者方法上添加注解@Transactional。

applicationContext.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:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/cache" xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/cache"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"
       http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/aop/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

        <!--加载properties文件 -->
        <context:property-placeholder location="classpath:c3p0-db.properties"/>
        <!--配置数据源,读取properties文件信息 -->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="${jdbc.driverClass}"></property>
            <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
            <property name="user" value="${jdbc.user}"></property>
            <property name="password" value="${jdbc.password}"></property>
        </bean>
        <!--配置JDBC模板 -->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="jdbcTemplate" ref="dataSource"></property>
        </bean>
        <!--配置dao -->
        <bean id="accountDao" class="cn.tm.dao.impl.AccountDaoImpl">
            <property name="jdbcTemplate" ref="jdbcTemplate"></property>
        </bean>
        <!--配置service -->
        <bean id="accountService" class="cn.tm.dao.impl.AccountServiceImpl">
            <property name="accountDao" ref="accountDao"></property>
        </bean>
        <!--事务管理器 -->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
        <!--注册事务管理驱动 -->
        <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
</beans>

AccountServiceImpl.java

package cn.tm.service.impl;
/*这里添加Transactional注解,并且使用注解的参数配置了事务详情,参数之间用逗号进行分隔*/
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,readOnly = false)
public class AccountServiceImpl implements AccountService{
    private AccountDao accountDao;
    public void setAccountDao(AccountDao accountDao){
        this.accountDao = accountDao;
    }
    @Override
    public void transfer(String outUser, String inUser, int money) {
        this.accountDao.out(outUser,money);
        this.accountDao.in(inUser,money);
    }
}

Spring的事务传播机制

Spring事务机制主要包括声明式事务和编程式事务。编程式不常用。

Spring声明式事务让我们从复杂的事务处理中得到解脱。使得我们再也无需要去处理获得连接、关闭连接、事务提交和回滚等这些操作。再也无需要我们在与事务相关的方法中处理大量的try…catch…finally代码。我们在使用Spring声明式事务时,有一个非常重要的概念就是事务属性。事务属性通常由事务的传播行为,事务的隔离级别,事务的超时值和事务只读标志组成。我们在进行事务划分时,需要进行事务定义,也就是配置事务的属性。

spring在TransactionDefinition接口中定义了七个事务传播行为:

(1)propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是最常见的选择。(默认)

(2)propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。

(3)propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。

(4)propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。

(5)propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

(6)propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。

(7)propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作。

那么看下面的例子:

(1)PROPAGATION_REQUIRED:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中。

现在有方法A和B,方法B在方法A中被调用,方法A、B上都有事务注解并为propagation_requierd级别,问单独调用方法A和B结果有什么不同?

如果单独调用B方法,因为没有事务,所以会先开启一个新的事务。

如果直接调用A方法,环境中没有事务,会开启一个新事务,当调用到方法B的时候,因为环境中已经有事务了,所以方法B就加入到了当前事务,不会新建事务了。

//事务属性 PROPAGATION_REQUIRED 
methodA{
    ...
    methodB();
}
//事务属性 PROPAGATION_REQUIRED 
methodB{
    ...
}

(2)PROPAGATION_SUPPORTS 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行。但是对于事务同步的事务管理器,PROPAGATION_SUPPORTS与不使用事务有少许不同。

情况跟上一个例子类似,也是两个方法,不过区别在于方法B的级别改成了propagation_supports,那么单独调用方法A和B结果有什么不同?

如果单独调用B方法,方法B是以非事务的方式执行的。

如果调用方法A,方法B会加入到方法A中,以事务的方式执行。

//事务属性 PROPAGATION_REQUIRED 
methodA{
    ...
    methodB();
}
//事务属性 PROPAGATION_SUPPORTS 
methodB{
    ...
}

(3)PROPAGATION_MANDATORY 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。

如果单独调用B方法,因为当前没有一个活动的事务,会抛出throw new IllegalTransactionStateException(“Transaction propagation ‘mandatory’ but no existing transaction found”);异常。

如果调用方法A,方法B会加入到方法A的事务中,事务的执行。

//事务属性 PROPAGATION_REQUIRED 
methodA(){ 
    methodB(); 
}
 
//事务属性 PROPAGATION_MANDATORY 
methodB(){ 
    …… 
}

(4)PROPAGATION_REQUIRES_NEW 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。使用PROPAGATION_REQUIRES_NEW,需要使用JtaTransactionManager作为事务管理器。

如果单独调用B方法,会开启一个新的事务,事务的执行。

如果调用方法A,当执行到方法B的时候,方法A的事务(事务A)会被挂起,方法B中创建一个事务(事务B),在事务B中执行,那么如果方法B成功处理,执行下面的doSomeThingB方法时,如果报错了,方法B的事务不会受到影响,方法A的代码除了方法B以外,都会回滚。

//事务属性 PROPAGATION_REQUIRED 
methodA(){ 
   doSomeThingA(); 
   methodB(); 
   doSomeThingB(); 
}
 
//事务属性 PROPAGATION_REQUIRES_NEW 
methodB(){ 
   …… 
}

(5)PROPAGATION_NOT_SUPPORTED  总是非事务地执行,并挂起任何存在的事务。使用PROPAGATION_NOT_SUPPORTED,也需要使用JtaTransactionManager作为事务管理器。(代码示例同上,可同理推出)

(6)PROPAGATION_NEVER 总是非事务地执行,如果存在一个活动事务,则抛出异常;

(7)PROPAGATION_NESTED如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行。

这是一个嵌套事务,使用JDBC 3.0驱动时,仅仅支持DataSourceTransactionManager作为事务管理器。需要JDBC 驱动的java.sql.Savepoint类。有一些JTA的事务管理器实现可能也提供了同样的功能。使用PROPAGATION_NESTED,还需要把PlatformTransactionManager的nestedTransactionAllowed属性设为true;而nestedTransactionAllowed属性值默认为false;

嵌套事务一个非常重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚。

如果单独调用方法B,会以propagation_requierd方式,即创建一个事务去执行。

如果调用方法A,如果方法A中代码报错,那么方法B中的事务也会回滚。(嵌套事务)

//事务属性 PROPAGATION_REQUIRED 
methodA(){ 
   doSomeThingA(); 
   methodB(); 
   doSomeThingB(); 
}
 
//事务属性 PROPAGATION_NESTED 
methodB(){ 
  …… 
}

参考:

1. 《SSH框架整合实战教程》

2.  https://www.cnblogs.com/myseries/p/10800430.html

持续更新!!!

免责声明:文章转载自《Spring的学习(四、Spring事务管理)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Struts2 中result type属性说明缓冲器的学习下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

单片机加密方法

                          单片机加密方法   在最近一个项目中,急急忙忙把功能完成就给了客户,完全没有安全意识,现在用烧录器把Flash里的程序一读,我就慌了,完全没有加密,随随便便就把程序读出来了,那我干了一个月的活,被人家花几秒钟读出来了,我这不是白干吗。因此,在这里普及一下安全意思,顺便介绍几种常见的加密方法。 一、打磨或更...

格式Table.TransformColumns(Power Query 之 M 语言)

数据源:         任意表,其中包含文本列 目标:         对文本列格式进行设置  操作过程:    选取文本列》【转换】》【格式】》选取        M公式:     = Table.TransformColumns( 表, {{"列名1", 转换函数1, 数据类型1},…,{"列名n", 转换函数n, 数据类型n}}, 剩余列转换函数,...

TP5动态路由配置好了但是报错was not found on this server的原因以及解决方法

问题:The requested URL /xxxx.html was not found on this server 原因:apache的重写未开启,开启重写后,问题解决, 方法如下: 1 apache 打开 httpd.conf 文件 找到AllowOverride None 改为 AllowOverride All...

深入理解JVM3

VM运行时数据区域 JVM执行Java程序的过程中,会使用到各种数据区域,这些区域有各自的用途、创建和销毁时间。根据《Java虚拟机规范(第二版)》的规定,JVM包括下列几个运行时数据区域: 1.程序计数器(Program Counter Register): 每一个Java线程都有一个程序计数器来用于保存程序执行到当前方法的哪一个指令,对于非Native...

spring事务配置步骤

spring事务配置流程 第一步:配置事务管理器 第二步:配置通知--》传播行为 第三步:配置切入点--》切面 AOP <!-- 事务管理器 --> <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager">...

ng-repeat循环输出简单案例

<!doctype html> <html ng-app> <head> <meta charset="utf-8"> <title>ng-repeat directive</title> </head> <body> <table ng-...