好吧,我承认,我蛋疼了。真的很疼很疼。。公司的项目不许用ssh,也不许用ssi... 1>好吧。。action写个调度还是比较easy的..用了三天把调度了,采用的是struts2的思想,一个reuquest一个实例,不过没有为action产生代理。。这个我想也没啥好蛋疼的。。 2> 连结池采用的是c3po,自己写连接池管理器。。 3> 也就是今天碰到的问题:事务..... 加事务啊。在service控制事务目前蛋疼中.... 问题:
1。如何保证同一个事务方法中所有dao 用的是同一个connection??
2。保证嵌套事务????? 其它问题暂时未知ing....... 目前想法:
1: 用事务的方法第一行,开启事务ThreadLocal保存开启事务后的connection..然后将ThreadLocal,放到context中(缓存中)..在各个dao里面,直接从context中获取connection....不知道可不可行??是个大大的XXXXX
2> 用一个count来记录事务的层数? 每嵌套一层+1. 提交一次-1 最后为0时,就connection.commit()????
求大牛指点。
单例模式穿件单例类
汗连接数据库的Connection变成了单例那你真是个人才。。
你这么做不是累死
参考之:http://developer.51cto.com/art/200906/129854.htm
session = dbPool.openSession();
try {
session.beginTransaction();
someService.process(session);
otherSerivce.process(session);
session.commit();}
catch(Exception e) {
session.rollback()
}
finally {
session.close();
}class SomeSerivce {
public static void process(Session session) {
session.createSQLQuery("select * from ****");
....
}
}用 ThreadLocal 比较复杂
http://topic.csdn.net/u/20090323/17/29237aab-ee3e-4e16-b9c4-53856425022c.html请教一下,在纯的JDBC中,如何项目采用分层了DAO层,服务层和SERVLET控制层,,那么怎么在servlet中启用JDBC的事务?
http://topic.csdn.net/u/20080705/18/d894b5e5-8b7b-4560-af16-e4b9d8405681.html将connection存放在Threadlocal里和数据库连接池的区别
http://topic.csdn.net/u/20080731/22/9af1fa06-2c82-4790-bee0-0274a66f3ae9.html大家来讨论下业务层(BO)该做什么事?该怎样做事?
http://topic.csdn.net/u/20090528/21/160f4629-8985-4a05-89ed-7b4bdcf9bb0f.html多个线程共享一个connection的问题
http://topic.csdn.net/u/20071128/12/6f085b57-a1b5-4100-a036-f43ef5ab3f8c.html这里还有一个帖子,虽然涉及 JPA 的,但在 J2SE 环境下 JPA 与 JDBC 没啥区别:EJB3之JPA程序结构,完美的异常处理
http://topic.csdn.net/u/20090829/20/6e73877e-af46-4f98-9fce-f574495b550c.html声明一下,我不认同这位帖主的做法(其采用 Runnable 接口),不过可以借鉴一下,作为一种思路也行。---------------------------------------------------------------------------------------下面的代码是我实现的事务上下文,之前在实际当中应用过,后来由于其他原因就没有用了,代码量很大,有兴趣的话供为参考:我们系统中也要用到,不过我们是使用 JPA 的,但是 JPA 在 J2SE 环境中跟 JDBC 没啥区别,下面这些是我的关键类和代码:JpaEntityManager 管理类,从该类产生 EntityManager 对象,管理当前线程中绑定的对象:import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;import net.blogjava.frankiegao123.log.Log;
import net.blogjava.frankiegao123.log.Logger;/**
* JPA EntityManager 管理工具<br />
*
* 从 EntityManagerFactory 获得 EntityManager 对象并绑定到当前线程中,以便进行事务管理
*
* @author frankiegao123
* 2009-10-30 下午12:16:41
*/
public class JpaEntityManager { private static Log log = Logger.getLog(JpaEntityManager.class); private static EntityManagerFactory factory; /**
* 本地线程容器
*/
private static ThreadLocal<EntityManager> entityManagerThreadBind = new ThreadLocal<EntityManager>(); static {
try {
// 初始化 EntityManagerFactory
factory = Persistence.createEntityManagerFactory(Config.getInstance().getJpaUnitName());
} catch(Exception e) {
log.error("EntityManagerFactory init failed", e);
}
} private JpaEntityManager() {
} /**
* 从当前线程中获得已经绑定在线程上的 EntityManager 对象
* @return
* @author frankiegao123
* 2009-10-30 下午12:35:15
*/
public static EntityManager getEntityManager(){
EntityManager entityManager = findThreadEntityManager();
if(entityManager == null) {
// 没有绑定时,抛出异常
throw new ThreadEntityManagerException("EntityManager cannot be found from current thread");
}
log.info("find EntityManager: {0} from current thread", entityManager);
return entityManager;
} /**
* 关闭当前线程中的 EntityManager 对象,同时清空当前线程中 EntityManager,便于下次重新绑定执行事务
*
* @param entityManager
* @author frankiegao123
* 2009-10-30 下午12:37:11
*/
static void closeEntityManager(EntityManager entityManager) {
EntityManager em = findThreadEntityManager();
log.debug("current thread EntityManager: {0}, parameter EntityManager: {1}", em, entityManager);
if(em == null) {
log.warn("EntityManager object in current thread is null, Using method invoke parameter EntityManager: {0}", entityManager);
em = entityManager;
}
em.close();
log.debug("EntityManager object close success");
entityManagerThreadBind.set(null);
log.info("current EntityManager object has been closed and the object in ThreadLocal has been set null");
} /**
* 获得新的 EntityManager 对象,并绑定到当前线程中
*
* @return
* @author frankiegao123
* 2009-10-30 下午12:38:15
*/
static EntityManager bindThreadEntityManager() {
EntityManager preEntityManager = findThreadEntityManager();
if(preEntityManager != null) {
// 当前线程中还存在之前没有被处理的 EntityManager 对象
log.warn("pre EntityManager not be closed, EntityManager: {0}", preEntityManager);
closeEntityManager(preEntityManager);
}
EntityManager entityManager = factory.createEntityManager();
setEntityManager(entityManager);
log.debug("EntityManager object was binded to current thread, EntityManager: {0}", entityManager);
return entityManager;
} /**
* 从本地线程中获得 EntityManager 对象
* @return
* @author frankiegao123
* 2009-10-30 下午12:18:44
*/
private static EntityManager findThreadEntityManager() {
return entityManagerThreadBind.get();
} private static void setEntityManager(EntityManager entityManager) {
entityManagerThreadBind.set(entityManager);
}
}TransactionProxy 使用 JDK 的 Proxy 实现 AOP 用于给业务类加上事务处理(这代码比较多,放在楼下)下面这些是业务事务代理工厂类 ServiceFactory,业务接口 Service, 实现类 GaoService,DAO 类 GaoTestDao,以及 JpaBaseDao 的代码:public class ServiceFactory { private static Service service = null;
static {
service = TransactionProxy.delegate(Service.class, new GaoService());
}
public static Service getService() {
return service;
}
}public interface Service {
public GaoTest process(Lottery lottery);
}class GaoService implements Service {
private static int k = 3000;
private static Log log = Logger.getLog(GaoService.class);
public GaoTest process(Lottery lottery) {
GaoTest gt = new GaoTest();
gt.setName(lottery.getCode());
gt.setTime(new Date());
GaoTestDao dao = new GaoTestDao();
dao.persist(gt);
GaoTest t = dao.find("c229e808-f1ce-4bab-9af0-9637e3c2c487");
if(t != null) {
t.setName("Gao" + (k++));
}
dao.merge(t);
return gt;
}
}public class GaoTestDao extends JpaBaseDao<GaoTest> {
@SuppressWarnings("unchecked")
public List<GaoTest> findGaoTestByName(String name) {
String jpql = "SELECT t FROM GaoTest t WHERE t.name = :name";
EntityManager em = JpaEntityManager.getEntityManager();
Query q = em.createQuery(jpql).setParameter("name", name);
return q.getResultList();
}
}import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;import javax.persistence.EntityManager;public class JpaBaseDao<T> implements BaseDao<T> {
private Class<T> entityClass;
@SuppressWarnings("unchecked")
public JpaBaseDao() {
Type genType = getClass().getGenericSuperclass();
Type[] params = ((ParameterizedType)genType).getActualTypeArguments();
entityClass = (Class)params[0];
} public T find(Serializable id) {
EntityManager em = JpaEntityManager.getEntityManager();
return em.find(entityClass, id);
} @SuppressWarnings("unchecked")
public List<T> getAll() {
EntityManager em = JpaEntityManager.getEntityManager();
String jpql = "SELECT t FROM " + entityClass.getName() + " t";
return em.createQuery(jpql).getResultList();
} public void merge(T t) {
EntityManager em = JpaEntityManager.getEntityManager();
em.merge(t);
} public void persist(T t) {
EntityManager em = JpaEntityManager.getEntityManager();
em.persist(t);
em.flush();
} public void remove(T t) {
EntityManager em = JpaEntityManager.getEntityManager();
em.remove(t);
}
}未完,接下楼
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;import net.blogjava.frankiegao123.log.Log;
import net.blogjava.frankiegao123.log.Logger;/**
* 事务代理
* @author frankiegao123
* 2009-10-30 上午10:25:57
*/
public class TransactionProxy { private static Log log = Logger.getLog(TransactionProxy.class); @SuppressWarnings("unchecked")
public static <T> T delegate(Class<T> clazz, Object obj) {
if(!isRequiredTransaction(obj.getClass())) {
log.debug("[{0}] never transaction", obj.getClass().getSimpleName());
return (T)obj;
}
log.debug("[{0}] require transaction", obj.getClass().getSimpleName());
// 返回代理对象
return (T)Proxy.newProxyInstance(
obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),
new XAInvocationHandle(obj)
);
} /**
* 检查某一对象是否需要使用事务
* @param obj
* @return
* @author frankiegao123
* 2009-10-30 上午10:26:58
*/
private static boolean isRequiredTransaction(AnnotatedElement obj) {
TransactionAttribute type = obj.getAnnotation(TransactionAttribute.class);
if((type == null) || TransactionAttributeType.REQUIRED.equals(type.value())) {
return true;
}
return false;
} private static void logArguments(Object obj, Method method, Object[] args) {
if(log.isDebugEnabled()) {
if(args == null || args.length == 0) {
log.debug("[{0}#{1}] invoke params is empty", obj.getClass().getSimpleName(), method.getName());
return;
}
StringBuilder sb = new StringBuilder();
for(int i = 0; i < args.length; i++) {
if(i > 0) {
sb.append(", ");
}
sb.append(args[i].getClass().getSimpleName()).append(": ").append(args[i]);
}
log.debug("[{0}#{1}] invoke params: ", obj.getClass().getSimpleName(), method.getName(), sb.toString());
}
} /**
* 使用 JDK 动态代理织入事务处理
* @author frankiegao123
* 2009-10-30 上午11:56:47
*/
private static class XAInvocationHandle implements InvocationHandler { private Object delegate; public XAInvocationHandle(Object delegate) {
this.delegate = delegate;
} public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
logArguments(delegate, method, args); if(isRequiredTransaction(method)) {
// 需要事务处理
log.debug("[{0}#{1}] method require transaction", delegate.getClass().getSimpleName(), method.getName());
return invokeWithTransactionRequired(proxy, method, args);
} else {
// 不需要事务处理
log.debug("[{0}#{1}] method never transaction", delegate.getClass().getSimpleName(), method.getName());
return invokeWithTransactionNever(proxy, method, args);
}
} private Object invokeWithTransactionNever(Object proxy, Method method, Object[] args) throws Throwable {
Object obj = null;
EntityManager em = null;
try {
em = JpaEntityManager.bindThreadEntityManager();
obj = method.invoke(delegate, args);
} catch(Throwable e) {
log.error("[invokeWithTransactionNever] invoke error", e);
throw e;
} finally {
if(em != null) {
JpaEntityManager.closeEntityManager(em);
}
}
return obj;
} private Object invokeWithTransactionRequired(Object proxy, Method method, Object[] args) throws Throwable {
EntityManager em = null;
EntityTransaction transaction = null;
Object obj = null;
try {
em = JpaEntityManager.bindThreadEntityManager();
transaction = em.getTransaction();
transaction.begin();
log.info("[{0}#{1}] EntityManager: {2}", delegate.getClass().getSimpleName(), method.getName(), em);
log.debug("[{0}#{1}] transaction begin, isActive: {2}", delegate.getClass().getSimpleName(), method.getName(), transaction.isActive());
obj = method.invoke(delegate, args);
log.debug("[{0}#{1}] transaction commit start, isActive: {2}", delegate.getClass().getSimpleName(), method.getName(), transaction.isActive());
transaction.commit();
if(log.isDebugEnabled()) {
log.debug("[{0}#{1}] transaction commit end, isActive: {2}", delegate.getClass().getSimpleName(), method.getName(), transaction.isActive());
}else if(log.isInfoEnabled()){
log.info("[{0}#{1}] transaction commit success", delegate.getClass().getSimpleName(), method.getName());
}
} catch (Throwable e) {
if(transaction != null && transaction.isActive()) {
log.error("[{0}#{1}] transaction rollback start, isActive: {2}", delegate.getClass().getSimpleName(), method.getName(), transaction.isActive());
transaction.rollback();
log.error("[{0}#{1}] transaction rollback ok, isActive: {2}", delegate.getClass().getSimpleName(), method.getName(), transaction.isActive());
} else {
log.error("[{0}#{1}] transaction is null or transaction is not active", delegate.getClass().getSimpleName(), method.getName());
}
log.error("[invokeWithTransactionRequired] invoke error", e);
throw e;
} finally {
if(em != null) {
JpaEntityManager.closeEntityManager(em);
}
}
return obj;
}
}
}如果是 JDBC 的话,只要把 EntityManager 改成 Connection 就差不多了下面这个是测试类,根据测试代码的 DEBUG 日志输出结果,以及手工加入异常时,JPA 操作均在事务管理之下:public class TransactionTest { public static void main(String[] args) {
for(int i = 0; i < 10; i++) {
new MultiThreadTest().start();
}
} private static class MultiThreadTest extends Thread {
public void run() {
for(int i = 0; i < 10; i++) {
try {
Lottery lottery = new Lottery();
lottery.setCode(Thread.currentThread().getName() + "_" + i);
Service service = ServiceFactory.getService();
GaoTest t = service.process(lottery);
System.out.println(t);
}catch(Exception e) {
e.printStackTrace();
}
}
}
}
}
hibernate和ibatis都不能用的话。自己从连接池里拿出connection然后放在ThreadLocal里面自己管理啊。只有这个办法了。 可以写一个工具类嘛,保证一个线程里拿到的Connection是同一个。
不让我用spring,那我只有走人了。