- 浏览: 318167 次
- 性别:
- 来自: 深圳
-
文章分类
最新评论
-
every:
真JB坑爹,标题redhat6 结果用的时5.3 ,尼玛标 ...
RedHat Linux 6企业版开启VNC Server远程桌面 -
okooo00:
五年光景蹉跎,最终还是烂尾了,从此人生又少了一样追求
《凡人修仙传》点评 -
mikey_5:
原来是这样子判断数据格式的,Thanks
POI读取Excel浅谈 -
jveqi:
tracy_meimei 写道楼主,我试过N多次了,在我的my ...
MyEclipse6.5 下Axis2插件的下载和安装 -
jsx112:
...
MySQL select into和SQL select into
AOP(Aspect Oriented Programming,面向方面编程)是如今比较火的概念之一,再加上Spring框架的流行,很多程序员更是言必称AOP,如果对AOP不了解就像土老帽似的。AOP中的Aspect其实就是程序员关注的某一方面,如某些方法有没有被访问过、某些方法执行时间有多长、把某些方法的执行置于事务之下等等,具体实现方法就是在某些方法执行前后自动执行一些操作,就像拦截器一样。其实一些框架中的拦截器功能正是通过AOP实现的。
Java反射功能中有一项就是动态代理,但代理的对象必须实现了接口,也就是Jdk目前仅支持接口的代理。其原理是首先检索被代理对象的所有接口,然后动态生成一个实现了被代理对象接口的Class(这也是为什么叫动态代理的原因),最后把这个Class的一个实例返回。因为通过Java动态代理之后,您所使用的对象就像狸猫换太子一样被掉包了,执行一个方法时,其实是执行的动态生成实例的方法,里面会有一个地方调用原对象的方法,从而达到在原对象方法执行前后运行特定代码的目的。在Spring中,利用了cglib,如果被代理对象实现了接口,就用Java的动态代理,如果仅仅是一个没有接口的类,则用cglib中继承的方式进行代理。
在Spring中有用Java注解(annotation)的方法实现事务管理的功能,也就是声明式事务,去除了代码中繁琐的事务控制代码。在本文中,利用Java的annotation、dynamic proxy实现一个简单的管理数据库连接与事务的框架,而不使用任何现成的框架。
首先是一个获取数据库连接的工具类,此处是使用的是mysql数据库,运行时需要mysql的jdbc驱动包。代码如下:
package demo.dynamicproxy;
import java.sql.Connection;
import java.sql.DriverManager;
public class DbUtil {
/**
* 获取数据库连接,如果使用其他数据库,修改这里就可以了。
* @return
*/
public static Connection getConnection() {
Connection conn = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/st", "root", "");
}
catch(Exception e) {
e.printStackTrace();
}
return conn;
}
}
对于需要数据库操作的业务类,需要实现IDb接口:
package demo.dynamicproxy;
import java.sql.Connection;
public interface IDb {
/**
* 设置数据库连接
* @param conn
*/
void setConnection(Connection conn);
/**
* 获取数据库连接。
* 如果没有设置返回null。
* @return
* @throws Exception
*/
Connection getConnection();
/**
* 释放数据库连接
* @param conn
* @throws Exception
*/
void closeConnection();
}
为了使用方便,建立一个IDb接口的默认实现类:
package demo.dynamicproxy;
import java.sql.Connection;
import java.sql.Statement;
public class DbImpl implements IDb {
private Connection conn;
@Override
public void closeConnection() {
try {
if (conn != null) conn.close();
conn = null;
System.out.println("close conn");
}
catch(Exception e) {
e.printStackTrace();
}
}
@Override
public Connection getConnection() {
return conn;
}
@Override
public void setConnection(Connection conn) {
this.conn = conn;
System.out.println("set conn");
}
protected int executeNonQuery(String sql) throws Exception {
System.out.println("executeNonQuery begin:" + sql);
Statement stmt = null;
int result = 0;
try {
stmt = getConnection().createStatement();
result = stmt.executeUpdate(sql);
}
catch(Exception e) {
throw e;
}
finally {
if (stmt != null) stmt.close();
}
System.out.println("executeNonQuery complete:" + sql);
return result;
}
}
对于需要数据库连接和事务的方法,加上一个注解就可以了,这就是那个注解:
package demo.dynamicproxy.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 被注解的方法可以自动获取数据库连接并开启事务。
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Transactional {
boolean autoCommit() default false;
}
被代理方法执行时的处理器,动态代理的核心就在这里:
package demo.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.sql.Connection;
import demo.dynamicproxy.annotation.Transactional;
/**
* 自动处理数据库连接、事务的调用处理器
*/
public class TransactionalInvocationHandler implements InvocationHandler {
private Object target;
private IDb db;
/**
* 构造方法
* @param target
*/
public TransactionalInvocationHandler(Object target) {
this.target = target;
this.db = (IDb) target;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("method invoke begin:" + method.getName());
Object result = null;
boolean isNeedTransaction = false;
boolean isAutoCommit = false;
if (method.isAnnotationPresent(Transactional.class)) {
isNeedTransaction = true;
isAutoCommit = method.getAnnotation(Transactional.class).autoCommit();
}
boolean isLocalOpen = false;
boolean rollback = false;
Connection conn = db.getConnection();
System.out.println("isNeedTransaction:" + isNeedTransaction);
System.out.println("isAutoCommit:" + isAutoCommit);
System.out.println("isLocalOpen:" + isLocalOpen);
try {
if (isNeedTransaction) {
if (conn == null) {
isLocalOpen = true;
try {
conn = DbUtil.getConnection();
if (conn == null) throw new Exception("数据库连接获取错误");
conn.setAutoCommit(isAutoCommit);
}
catch (Exception e) {
throw e;
}
db.setConnection(conn);
}
}
result = method.invoke(this.target, args);
}
catch(Exception e) {
rollback = true;
e.printStackTrace();
throw e;
}
finally {
if (conn != null && isLocalOpen) {
if (!isAutoCommit) {
if (rollback) conn.rollback();
else conn.commit();
}
db.closeConnection();
}
}
System.out.println("method invoke complete:" + method.getName());
return result;
}
}
获取代理对象的工厂类:
package demo.dynamicproxy;
import java.lang.reflect.Proxy;
public class DefaultProxyFactory {
@SuppressWarnings("unchecked")
public static <T> T createProxy(T target) throws Exception {
if (!(target instanceof IDb)) throw new Exception("target must be instance of IDb");
ClassLoader classLoader = target.getClass().getClassLoader();
Class<?>[] interfaces = target.getClass().getInterfaces();
TransactionalInvocationHandler handler = new TransactionalInvocationHandler(target);
return (T) Proxy.newProxyInstance(classLoader, interfaces, handler);
}
}
至此,一个简单的框架就完成了。为了测试是否好用,做一个简单的例子,每个访问数据库的业务类都需要一个接口:
package demo.business;
import demo.dynamicproxy.annotation.Transactional;
public interface IDml {
void insert() throws Exception;
void update() throws Exception;
void delete() throws Exception;
void select() throws Exception;
@Transactional(autoCommit=false)
void execute() throws Exception;
}
业务类既需要实现业务接口,又需要实现IDb接口:
package demo.business;
import java.sql.ResultSet;
import java.sql.Statement;
import demo.dynamicproxy.DbImpl;
import demo.dynamicproxy.DefaultProxyFactory;
public class Dml extends DbImpl implements IDml {
@Override
public void delete() throws Exception{
executeNonQuery("delete from t where id=2");
System.out.println("delete 2");
}
@Override
public void execute() throws Exception{
System.out.println("begin");
insert();
update();
//if (true) throw new Exception("an error"); //此处测试异常
select();
delete();
}
@Override
public void insert() throws Exception{
executeNonQuery("insert into t(id) values(1)");
System.out.println("insert 1");
}
@Override
public void select() throws Exception{
Statement stmt = null;
ResultSet rs = null;
try {
stmt = getConnection().createStatement();
rs = stmt.executeQuery("select id from t");
while (rs.next()) {
System.out.println("select :" + rs.getString("ID"));
}
}
catch(Exception e) {
throw e;
}
finally {
if (rs != null) rs.close();
if (stmt != null) stmt.close();
}
}
@Override
public void update() throws Exception{
executeNonQuery("update t set id=2 where id=1");
System.out.println("update 2");
}
public static void main(String[] args) {
try {
Dml dmlImpl = new Dml();
IDml dml= DefaultProxyFactory.createProxy(dmlImpl);
dml.execute();
Thread.sleep(20000); //延迟程序退出,可以查看数据库连接有没有释放
System.out.println("over");
}
catch(Exception e) {
e.printStackTrace();
}
}
}
main方法中是一个使用业务对象进行业务处理的例子。这样,程序就可以运行了,在测试时可以在mysql数据库中执行“show full processlist;”查看数据库连接情况。在使用时,主要注意在业务对象的接口方法中加上注解“@Transactional”,获取的业务对象需要从工厂中获得“IDml dml= DefaultProxyFactory.createProxy(dmlImpl);”。
这样一个简单的框架也许没有什么用,在实际项目应用时有现成的开源框架可以用,但可以学习框架实现的原理,对知识有更加深入的了解。
使用动态代理方法可以获得代码上的简洁,缺陷是牺牲了程序执行的效率,在对效率要求不太高的地方可以使用。
发表评论
-
Mina开发笔记
2014-12-08 20:08 0import java.nio.charset.Ch ... -
Excel中日期与数字的转换代码
2014-05-30 23:24 2794public static void main(St ... -
求一个月有几周
2013-02-22 18:19 1213int year = 2013; int month= ... -
The error is weblogic.descriptor.DescriptorException: Unmarshaller failed
2012-09-13 11:58 2338部署 web project 到weblogic92(换成10 ... -
ecllipse无法启动,一直停留刚开始启动界面
2012-07-18 11:47 24341、 故障发生原因 :由于电脑配置较差 ,经常死机 或者 ... -
启动JBOSS,提示错误1098端口被占用的解决方案
2012-06-25 10:25 1812问题:启动JBOSS,提示错误1098端口被占用 方案一: ... -
Version 1.3.1_01 of the JVM is not suitable for this product.Version:1.4.1 or gr
2012-05-30 17:06 1173Version 1.3.1_01 of the JVM is ... -
java.lang.AbstractMethodError: com.microsoft.jdbc.base.BaseDatabaseMetaData.supp
2012-04-10 21:51 1993java.lang.AbstractMethodError: ... -
org.apache.axis2.databinding.utils.BeanUtil.getPullParser错误
2012-03-28 12:56 1961在开发ssh+axis2的webservice应用中,报这个错 ... -
增加eclipse启动的Tomcat内存的
2011-09-30 10:04 8937JAVA程序启动时JVM都会分配一个初始内存和最大内存给这 ... -
java.lang.OutOfMemoryError: PermGen space及其解决方法
2011-09-26 10:02 12711、 PermGen space的全称 ... -
POI读取Excel浅谈
2011-09-24 15:30 3022先看代码,挨句解释: 一般遍历使用两种方式,1:得到总的行数 ... -
POI读取EXCEL教程
2011-09-24 14:22 1874一、Excel基础 二、HSSF概况 三、通过user ... -
有关java中的Date,String,Timestamp之间的转化问题
2011-09-22 17:10 1469一.获取系统当前时间: 1.System.out.print ... -
Hibernate温习(4)--三大类查询总结
2011-09-14 12:49 1386[url]Hibernate目前总共分为三大类查询:creti ... -
hibernate 关系映射 annotation 版
2011-09-06 16:29 1564关于mappedBy 双向关联 ... -
hibernate+spring 注解 对事务的一些信息
2011-09-06 16:27 1641事务注解说明@Transactional 类事务说明机制 ... -
JPA一对多,多对多映射
2011-09-03 23:46 4077JPA(Java Persistence API)是Sun ... -
Rational Rose 生成java代码
2011-08-25 10:26 1975一,正向工程 1、设置默认语言为Java,Tools- ... -
SOA服务设计原则-转载
2011-08-24 10:27 1160这一部分是有关整个 SOA 系统的指南,代表了在建立系统时需要 ...
相关推荐
在数据库连接池的例子中,动态代理可以用来创建一个代理数据库连接,这个代理在获取连接时,可以自动地进行连接池的管理和资源调度。 在实际的数据库连接池实现中,我们通常会有一个`ConnectionPool`类作为装饰器,...
在本项目"JAVA SWing 实现C/S模式的数据库编程及WebServices 调用实现"中,开发者可能已经创建了一个Java Swing应用程序,该应用具有用户界面,允许用户进行数据操作。这些操作可能包括添加、删除、更新数据库记录。...
在IT行业中,数据库操作是应用程序的核心部分,而Hibernate作为一款流行的Java ORM(对象关系映射)框架,极大地...在大型项目中,使用代理实现的自动事务管理是最佳实践之一,因为它提高了代码的可测试性和可扩展性。
在本示例中,我们将探讨如何使用MyBatis通过JDBC连接到SQL Server数据库,并进一步学习如何利用MyBatis的动态代理机制生成Mapper接口的实现。 首先,我们需要在项目中引入MyBatis和SQL Server的JDBC驱动依赖。通常...
这个文件名可能表示一个具体的示例或类,可能是关于如何在 Spring 中使用动态代理来实现数据库连接池的管理。连接池是数据库操作中常见的优化手段,动态代理可以用于监控连接的获取与释放,或者在每次连接使用前后...
BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接池的性能,根据某些测试数据发现,BoneCP是最快的连接池。BoneCP很小,只有四十几K(运行时需要slf4j和guava的支持,这二者加...
在本示例中,我们将深入探讨如何利用Spring框架与JDBC的整合来实现转账业务,并通过动态代理模式来优化事务管理。动态代理模式是Java中一种强大的设计模式,它允许我们在运行时创建对象的代理,以拦截方法调用并执行...
Druid与SpringBoot的整合,使得数据库连接资源管理更加高效和稳定。 ClickHouse是一款开源的列式数据库管理系统(Column-Oriented DBMS),专为在线分析处理(OLAP)设计,具有极高的读写速度和极低的延迟。...
在本项目中,我们探讨的是一个基于Java技术的幼儿园管理系统,该系统旨在提供全面的信息化管理解决方案,以满足幼儿园日常运营的需求。以下是该项目的核心知识点: 1. **Java编程语言**:作为项目的基石,Java以其...
总结,本项目展示了如何在Spring MVC和Hibernate环境中实现事务管理,通过MyEclipse自动生成的包和配置文件,简化了开发流程。在实际应用中,这样的整合能够提供高效且易于维护的Web应用,同时,声明式事务管理极大...
在ORM框架中,通常会使用动态代理或者模板方法来根据Java对象的方法调用生成对应的SQL语句。这涉及到反射API的使用,以及对SQL语法的理解和抽象。 此外,事务管理也是ORM框架中不可或缺的一部分。作者可能会讨论...
Spring通过Bean配置或Java配置方式,可以将连接池集成到应用中,并且可以在Spring的事务管理中透明地使用连接池,从而实现数据库连接的自动获取和释放。 以下是SSH整合连接池的基本步骤: 1. 添加连接池依赖:在...
本教程将详细介绍如何在Spring框架中利用AOP实现对Hibernate的自动事务管理,以便于提升开发效率和代码的可维护性。 首先,理解Spring AOP的核心概念。AOP允许程序员定义"切面",这些切面可以包含业务逻辑的各个...
3. **利用设计模式**:例如使用代理模式(Proxy Pattern)来增强业务逻辑对象的功能,使其能够自动处理事务管理,同时保持业务逻辑的简洁性。 #### 七、总结 事务处理是企业级应用开发中不可或缺的一部分,合理的...
动态代理是AOP实现的一种常见手段,特别是在Java中。动态代理允许我们在运行时创建代理对象,这个代理对象可以代表原对象执行相同的方法,同时在调用前后添加额外的功能。Java中的动态代理有两种实现:一种是通过`...
ShardingSphere内置了Druid和HikariCP两种高性能的数据库连接池,确保在并发环境下数据库连接的有效管理和高效利用,提升系统整体性能。 5. **分布式数据库治理**: 除了数据分片,ShardingSphere还提供了分布式...
Spring框架的事务管理机制是在Java开发环境中非常重要的一个组成部分,它能够帮助开发者简化事务处理的复杂度,提高应用程序的一致性和可靠性。Spring事务管理的核心是基于AOP(面向切面编程)来实现的。 **Spring...
在Java中,动态代理主要通过java.lang.reflect包中的Proxy和InvocationHandler接口实现。Proxy类提供了创建动态代理对象的方法,而InvocationHandler接口定义了处理代理对象方法调用的逻辑。 AOP(面向切面编程)是...
BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接池的性能,根据某些测试数据发现,BoneCP是最快的连接池。BoneCP很小,只有四十几K(运行时需要slf4j和guava的支持,这二者加...