Spring有几种事务处理方式?举例说明

本文介绍了三种Spring框架下实现事务管理的方法:使用TransactionProxyFactoryBean、tx/aop命名空间配置及@Transactional注解的方式,并提供了具体的代码示例。

1、用原始的transactionfactorybean的,代理dao事务处理
2、用aop:config声明要进行事务增强的切面,用tx:advice声明具体方法的事务属性,及应用到的事务管理器
3、使用@transactional注解配置声明事务
如有一代表用户的域对象user:
package com.domain;
import java.io.serializable;
public class user implements serializable{
    private int user_id;
    private string user_name;
    private string user_password;
    private string user_desc;
....//省略set、get方法
}
user的数据库操作接口:
package com.dao;
import com.domain.user;
public interface userdao {
    public void adduser(user user);
}
有一继承spring jdbc支持类的userdao接口实现类,实现添加一个user的方法。它需要注入一个spring jdbc模板类jdbctemplate:
package com.dao.jdbc;
import com.domain.user;
import com.dao.userdao;
import org.springframework.jdbc.core.support.jdbcdaosupport;
public class userjdbcdao extends jdbcdaosupport implements userdao{
    public void adduser(user user){
         string  sql =
         "insert into user(user_name,user_password,user_desc) values(?,?,?)";
        object[] params = new object[]{
           user.getuser_name(),
           user.getuser_password(),
           user.getuser_desc()
        } ;
        this.getjdbctemplate().update(sql, params);
    }
}
以上dao层的类对应的bean的基本配置文件app_dao.xml如下(数据源的属性放入了外部的资源文件"prop.properties"):
    <bean class="org.springframework.beans.factory.config.propertyplaceholderconfigurer">
        <property name="location" value="classpath:prop.properties"/>
    </bean>
<!--数据源-->
    <bean id="datasource" class="org.apache.commons.dbcp.basicdatasource"
     destroy-method="close">
        <property name="driverclassname" value="${jdbc.driverclassname}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
<!--spring jdbc模板bean,它注入了上面的数据源-->
    <bean id="jdbctemplate" class="org.springframework.jdbc.core.jdbctemplate">
        <property name="datasource" ref="datasource"/>
    </bean>
<!--user数据操作的bean声明,它注入了上面的spring jdbc模板bean:jdbctemplate-->
    <bean id="userjdbcdao"
    class="com.dao.jdbc.userjdbcdao">
 <property name="jdbctemplate" ref="jdbctemplate"/>
    </bean>
</beans>

这里我简单地模拟业务类(业务接口userservice省略):
package com.service.impl;
import com.dao.userdao;
import com.domain.user;
import com.service.userservice;
public class userserviceimpl implements userservice {
    private userdao userdao;
    public void setuserdao(userdao userdao){
        this.userdao = userdao;
    }
    public void adduser(user user){
        this.userdao.adduser(user);
    }
}
为了在业务类中使用事务管理功能,有如下几个方法:
1、用原始的transactionfactorybean的app.xml基本配置:
    <import resource="classpath:app_dao.xml"/><!--导入dao层的配置-->
<!--spring jdbc的事务管理bean,引入了dbcp数据源-->
    <bean id="txmanager" class="org.springframework.jdbc.datasource.datasourcetransactionmanager">
        <property name="datasource" ref="datasource"/>
    </bean>
<!--业务类bean-->
    <bean id="userserviceimpltarget" class="com.service.impl.userserviceimpl">
        <property name="userdao" ref="userjdbcdao"/>
    </bean>
<!--应用原始的transactionfactorybean进行事务管理bean的声明-->
    <bean id="userserviceimpl"class="org.springframework.transaction.interceptor.transactionproxyfactorybean">
        <property name="transactionmanager" ref="txmanager"/><!--指定事务管理bean-->
        <property name="target" ref="userserviceimpltarget"/><!--指定业务bean-->
        <property name="transactionattributes"><!--事务的属性设置列表-->
            <props>
                <prop key="add*">propagation_required,isolation_serializable</prop>
                <!--设置事务为只读时,添加数据将会产生异常-->
                <!--<prop key="add*">propagation_required,isolation_serializable,readonly</prop>-->
            </props>
        </property>
    </bean>
测试:
......
userserviceimpl usi = (userserviceimpl)ctx.getbean("userserviceimpl");
......
2、用tx/aop命名空间配置:
<?xml version="1.0" encoding="utf-8"?>
<beans .....
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsp:schemalocation="http://www.springframework.org/schema/beans
    ...........
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
    <import resource="classpath:app_dao.xml"/>
    <bean id="txmanager" class="org.springframework.jdbc.datasource.datasourcetransactionmanager">
        <property name="datasource" ref="datasource"/>
    </bean>

    <bean id="userserviceimpltarget" class="com.service.impl.userserviceimpl">
        <property name="userdao" ref="userjdbcdao"/>
    </bean>
<!--应用tx/aop命名空间进行事务声明-->
<!--用tx:advice声明具体方法的事务属性,及应用到的事务管理器-->
    <tx:advice id="txadvice" transaction-manager="txmanager">
        <tx:attributes>
            <tx:method name="add*" read-only="true"/>
        </tx:attributes>
    </tx:advice>
<!--用aop:config声明要进行事务增强的切面-->
    <aop:config>
        <aop:pointcut id="servicemethod"
        expression="execution(* com.service..add*(..))"/>
        <aop:advisor pointcut-ref="servicemethod" advice-ref="txadvice"/>
    </aop:config>
</beans>
测试:
.......
userservice usi = (userservice)ctx.getbean("userserviceimpltarget");
..........
3、使用@transactional注解配置声明事务(最简单实用的方法):
在需要事务管理增强的业务类加入@transactional注解标记,如:
......
import org.springframework.transaction.annotation.transactional; //注解式事务
@transactional(readonly=false) //对业务类进行事务增强的标注
public class userserviceimpl implements userservice {
...........
}
再在配置文件中用<tx:annotation-driven>驱动自动为标记@transactional注解的类织入事务管理增强:
 <import resource="classpath:app_dao.xml"/>
    <bean id="txmanager" class="org.springframework.jdbc.datasource.datasourcetransactionmanager">
        <property name="datasource" ref="datasource"/>
    </bean>
    <!--注解式事务配置驱动-->
    <tx:annotation-driven transaction-manager="txmanager" proxy-target-class="true"/>
<!--业务类bean的实现类标注了@transactional注解,所以会被
tx:annotation-driven注解驱动自动织入事务增强-->
    <bean id="userservice" class="com.service.impl.userserviceimpl">
        <property name="userdao" ref="userjdbcdao"/>
    </bean>
测试:
.........
userserviceimpl usi = (userserviceimpl)ctx.getbean("userservice");

转载于:https://www.cnblogs.com/soundcode/archive/2010/12/19/1910302.html

<think>好的,我现在需要回答用户关于Java代理使用场景的问题,并且需要举例说明。首先,我要回忆一下用户之前的问题和我的回答。用户之前问过Java中的代理是什么,我介绍了静态代理、动态代理以及CGLib代理,并提到了实际应用场景,比如日志记录、事务管理、权限校验、延迟加载和AOP。现在用户希望具体举例说明哪种场景需要用到代理。 首先,我需要确定用户的需求。他们可能已经了解了代理的基本概念,现在需要具体例子来加深理解。因此,我应该选择几个典型的应用场景,详细说明每个场景下代理是如何工作的,以及为什么需要用到代理模式。同时,结合代码示例会更直观。 接下来,我需要考虑如何组织这些例子。可能按照之前提到的场景分点展开,每个场景给出一个具体的例子。比如,日志记录、事务管理、权限控制、延迟加载、性能监控和AOP。其中,AOP可能和前面的部分有重叠,需要特别注意不要重复。 然后,每个例子需要包括场景描述、为什么需要代理、代理如何实现以及代码示例。代码示例部分要注意用户之前的回答中使用了Java代码,所以这里也需要保持一致性,使用类似的风格,可能包括接口、目标类、代理类或InvocationHandler的实现等。 另外,用户之前的回答提到了静态代理和动态代理的区别,所以在举例时可能需要说明在不同情况下选择哪种代理方式更合适。例如,日志记录可能更适合动态代理,因为它可能被多个类使用,而静态代理可能在简单场景下使用。 需要注意的是,用户可能对某些术语不太熟悉,比如AOP,所以在解释时要简明扼要。同时,要确保代码示例的正确性,避免语法错误,并且注释清楚每个部分的作用。 现在,我需要检查是否有遗漏的场景或是否需要进一步细化某个例子。例如,延迟加载的具体实现可能需要用代理来拦截对数据的访问,当真正需要时才加载数据,这样可以提高性能。此外,权限控制可能涉及在方法调用前检查用户权限,如果不符合则拒绝执行。 在编写代码示例时,要确保它们简洁明了,能够突出代理的作用。例如,在日志记录的示例中,代理类在方法调用前后添加日志输出;在事务管理中,代理类负责开启和提交事务。 最后,总结部分需要强调代理模式的优势,如解耦、代码复用、灵活性等,并指出这些例子展示了代理在不同场景下的应用,帮助用户更好地理解何时使用代理模式。 现在,我需要将这些思考整理成结构化的回答,分点列出每个场景,并附上相应的说明和代码示例,确保逻辑清晰,易于理解。</think>在Java中,代理模式常用于**不修改原有代码**的前提下,通过代理对象间接增强功能。以下是需要代理的典型场景及具体示例: --- ### **场景1:日志记录** #### **需求** 记录方法调用信息(如参数、执行时间),但不侵入业务代码。 #### **代理实现** 通过动态代理在方法前后插入日志逻辑。 ```java // 接口 interface DataService { void processData(String data); } // 目标类 class DataServiceImpl implements DataService { public void processData(String data) { System.out.println("处理数据:" + data); } } // 动态代理:日志增强 class LoggingHandler implements InvocationHandler { private Object target; public LoggingHandler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long start = System.currentTimeMillis(); System.out.println("调用方法:" + method.getName() + ",参数:" + Arrays.toString(args)); Object result = method.invoke(target, args); // 执行原方法 long end = System.currentTimeMillis(); System.out.println("方法执行耗时:" + (end - start) + "ms"); return result; } } // 使用代理 DataService target = new DataServiceImpl(); DataService proxy = (DataService) Proxy.newProxyInstance( target.getClass().getClassLoader(), new Class[]{DataService.class}, new LoggingHandler(target) ); proxy.processData("test"); ``` **输出**: ``` 调用方法:processData,参数:[test] 处理数据:test 方法执行耗时:2ms ``` --- ### **场景2:事务管理** #### **需求** 在数据库操作前开启事务,执行后提交或回滚事务。 #### **代理实现** 通过代理统一管理事务边界。 ```java // 静态代理示例 class TransactionProxy implements UserService { private UserService target; private Connection connection; public TransactionProxy(UserService target, Connection connection) { this.target = target; this.connection = connection; } public void saveUser() { try { connection.setAutoCommit(false); // 开启事务 target.saveUser(); // 执行业务方法 connection.commit(); // 提交事务 } catch (SQLException e) { connection.rollback(); // 回滚事务 } } } ``` --- ### **场景3:权限控制** #### **需求** 拦截未授权用户对敏感方法的调用。 #### **代理实现** 动态代理检查用户权限: ```java class SecurityHandler implements InvocationHandler { private Object target; private String userRole; public SecurityHandler(Object target, String userRole) { this.target = target; this.userRole = userRole; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().equals("deleteData") && !"admin".equals(userRole)) { throw new RuntimeException("权限不足!"); } return method.invoke(target, args); // 放行合法操作 } } ``` --- ### **场景4:延迟加载(Lazy Loading)** #### **需求** 在访问大对象时,仅在真正需要时加载数据(如ORM框架中的懒加载)。 #### **代理实现** ```java // 使用CGLib生成代理 class LazyLoader implements MethodInterceptor { private Object realObject; // 真实对象(延迟初始化) private Supplier<Object> supplier; // 初始化逻辑 public LazyLoader(Supplier<Object> supplier) { this.supplier = supplier; } public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { if (realObject == null) { realObject = supplier.get(); // 首次调用时加载 } return method.invoke(realObject, args); // 转发到真实对象 } } // 使用示例 Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(HeavyResource.class); enhancer.setCallback(new LazyLoader(() -> loadFromDatabase())); // 延迟加载数据库数据 HeavyResource proxy = (HeavyResource) enhancer.create(); ``` --- ### **场景5:远程方法调用(RPC)** #### **需求** 调用远程服务时,隐藏网络通信细节(如序列化、发送请求)。 #### **代理实现** 动态代理将本地调用转为网络请求: ```java class RpcProxy implements InvocationHandler { private String serviceUrl; public RpcProxy(String serviceUrl) { this.serviceUrl = serviceUrl; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 1. 序列化参数 byte[] request = serialize(method.getName(), args); // 2. 发送网络请求 byte[] response = sendRequest(serviceUrl, request); // 3. 反序列化结果 return deserialize(response); } } ``` --- ### **总结** 代理模式的核心应用场景: 1. **解耦非业务逻辑**(如日志、事务、权限)。 2. **控制对象访问**(延迟加载、远程调用)。 3. **扩展功能无需修改原代码**(符合开闭原则)。 在Spring框架中,AOP(如`@Transactional`)正是通过动态代理实现这些场景的典型例子。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值