﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-foxty</title><link>http://www.blogjava.net/foxty/</link><description>技术blog</description><language>zh-cn</language><lastBuildDate>Wed, 15 Apr 2026 13:43:59 GMT</lastBuildDate><pubDate>Wed, 15 Apr 2026 13:43:59 GMT</pubDate><ttl>60</ttl><item><title>手工实现JDBC事务管理。</title><link>http://www.blogjava.net/foxty/archive/2006/05/22/47481.html</link><dc:creator>糊里糊涂</dc:creator><author>糊里糊涂</author><pubDate>Mon, 22 May 2006 07:52:00 GMT</pubDate><guid>http://www.blogjava.net/foxty/archive/2006/05/22/47481.html</guid><wfw:comment>http://www.blogjava.net/foxty/comments/47481.html</wfw:comment><comments>http://www.blogjava.net/foxty/archive/2006/05/22/47481.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/foxty/comments/commentRss/47481.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/foxty/services/trackbacks/47481.html</trackback:ping><description><![CDATA[最近由于项目原因，底层数据库访问都必须使用JDBC来操作，为了能更好的实现事务，而且也便于将来移植到Ibatis上去，在作设计的时候参照Ibatis的Dao模式来设计dao，然后事务控制就必须得自己手工来实现了。并且一起也实现了事务得嵌套。主要依靠2个类来实现。
<p>    1，TransactionUtil类，负责开启事务，提交事务以及关闭事务。</p><p>    2，Transaction类，用来记录当前事务得状态以及数据库连接。</p><p>   </p><table bordercolor="#cccccc" cellspacing="2" cellpadding="1" width="100%" bgcolor="#ffffff" border="1"><tbody><tr><td><p> package com.orizone.oa.extra.service;</p><p>import java.sql.Connection;<br />import java.sql.ResultSet;<br />import java.sql.SQLException;<br />import java.sql.Statement;</p><p>import net.orizone.oa.common.ConnectionPoolBean;</p><p>import org.apache.commons.logging.Log;<br />import org.apache.commons.logging.LogFactory;</p><p>import com.orizone.comm.util.BusinessException;</p><p>public class TransactionUtil <br />{<br /> private final static ThreadLocal local = new ThreadLocal();<br /> private static Log log = LogFactory.getLog(TransactionUtil.class);<br /> <br /> /**<br />  * 开启事务<br />  */<br /> public static void startTransaction()throws  BusinessException<br /> {<br />  Transaction tran = (Transaction)local.get();<br />  //判断此事务是否属于一个顶层事务。<br />  if(tran == null)<br />  {<br />   tran = new Transaction();<br />   //设置本地线程的connection<br />   Connection con = ConnectionPoolBean.getConnection();<br />   try<br />   {<br />    con.setAutoCommit(false);<br />   }catch(SQLException e)<br />   {<br />    e.printStackTrace();<br />    throw new BusinessException(e, "开启事务失败！");<br />   }<br />   tran.setConnection(con);<br />   tran.setCommitCount(0);<br />   tran.setTransCount(1);<br />   tran.setTransDeep(1);<br />   <br />   local.set(tran);<br />  }else<br />  {<br />   //事务已经开启，将嵌套层次深度加一，将事务次数加一<br />   tran.setTransCount(tran.getTransCount() + 1);<br />   tran.setTransDeep(tran.getTransDeep() + 1);<br />  }  <br /> }<br /> <br /> /**<br />  * 提交事务<br />  *<br />  */<br /> public static void commitTransaction()throws  BusinessException<br /> {<br />  Transaction tran = (Transaction)local.get();<br />  //如果事务属于嵌套，则不提交数据，直接将层次数减一。<br />  if(tran.getTransDeep() &gt; 1)<br />  {<br />   tran.setTransDeep(tran.getTransDeep() - 1);<br />   tran.setCommitCount(tran.getCommitCount() + 1);<br />   return;<br />  }<br />  <br />  Connection con = tran.getConnection();<br />  try<br />  {<br />   if(tran.hasFullExecute())<br />   {<br />    con.commit();   <br />   }<br />  }catch(SQLException e)<br />  {<br />   log.error(e);   <br />   throw new BusinessException(e, "提交事务失败!");<br />  }<br /> }<br /> <br /> /**<br />  * 结束事务<br />  *<br />  */<br /> public static void endTransaction()throws  BusinessException<br /> {<br />  Transaction tran = (Transaction)local.get();<br />  //如果事务属于嵌套，则不关闭连接，直接将层次数减一。<br />  if(tran.getTransDeep() &gt; 1)<br />  {<br />   tran.setTransDeep(tran.getTransDeep() - 1);<br />   return;<br />  }<br />  <br />  //当前事务已经结束，清空ThreadLocal变量，防止下一次操作拿到已经关闭的Connection对象。<br />  local.set(null);<br />  Connection con = tran.getConnection();<br />  try<br />  {<br />   if(!tran.hasFullExecute())<br />   {<br />    con.rollback();<br />   }<br />  }catch(SQLException e)<br />  {<br />   log.error(e);<br />   throw new BusinessException(e, "事务回滚失败!");<br />  }finally<br />  {<br />   try<br />   {<br />    con.close();<br />   }catch(SQLException se)<br />   {<br />    log.error(se);<br />    throw new BusinessException(se, "关闭事务失败!");<br />   }<br />  }<br />  <br /> }<br /> <br /> /**<br />  * 获取当前事务的数据库连接。<br />  * @return<br />  */<br /> public static Connection getConnection()<br /> {<br />  Transaction tran = (Transaction)local.get();<br />  Connection  con = tran.getConnection();<br />  if(con == null)<br />  {<br />   con = ConnectionPoolBean.getConnection();   <br />  }<br />  return con;<br /> }<br /> <br /> /**<br />  * 测试代码<br />  * @param args<br />  * @throws Exception<br />  */<br /> public static void main(String args[])throws Exception<br /> {<br />  test();<br />  test();<br /> }<br /> <br /> /**<br />  * 测试代码<br />  *<br />  */<br /> private static void test()<br /> {<br />  TransactionUtil.startTransaction();<br />  try<br />  {<br />   Connection con = TransactionUtil.getConnection();<br />   Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);<br />   stmt.executeUpdate("INSERT INTO bb(bb) values('bb')");<br />   stmt.executeUpdate("INSERT INTO aa(aa) values('aa')");<br />   //if(true) throw new Exception("");<br />   TransactionUtil.commitTransaction();<br />  }catch(Exception e)<br />  {<br />   e.printStackTrace();<br />   //throw new BusinessException("");<br />  }finally<br />  {<br />   TransactionUtil.endTransaction();<br />  }<br /> }<br />}</p></td></tr></tbody></table><p> </p><p></p><table bordercolor="#cccccc" cellspacing="2" cellpadding="1" width="100%" bgcolor="#ffffff" border="1"><tbody><tr><td><p>package com.orizone.oa.extra.service;</p><p>import java.sql.Connection;</p><p>public class Transaction <br />{<br /> //数据库连接对象<br /> private Connection connection;<br /> //事务次数<br /> private int transCount;<br /> //提交次数<br /> private int commitCount;<br /> //事务嵌套层次<br /> private int transDeep;</p><p> int getCommitCount() <br /> {<br />  return commitCount;<br /> }</p><p> void setCommitCount(int commitCount) <br /> {<br />  this.commitCount = commitCount;<br /> }</p><p> Connection getConnection() <br /> {<br />  return connection;<br /> }</p><p> void setConnection(Connection conn) <br /> {<br />  this.connection = conn;<br /> }</p><p> public int getTransCount() <br /> {<br />  return transCount;<br /> }</p><p> void setTransCount(int transCount) <br /> {<br />  this.transCount = transCount;<br /> }</p><p> int getTransDeep() <br /> {<br />  return transDeep;<br /> }</p><p> void setTransDeep(int transDeep)<br /> {<br />  this.transDeep = transDeep;<br /> }<br /> <br /> /**<br />  * 判断事务是否完全提交。<br />  * 通过提交次数和事务次数来判断事务是否完全提交。<br />  * @return<br />  */<br /> boolean hasFullExecute()<br /> {<br />  return commitCount + 1 == transCount;<br /> }</p><p>}<br /></p></td></tr></tbody></table><p> </p><p>代码中出现的ConnectionPoolBean是用来负责获取数据库连接的类。整个思想就是，将一个Transaction相关信息（数据库连接对象，事务次数，提交次数以及事务深度）放入到当前线程的ThradLocal当中，后面的操作都是基于这个事务基础的，这样才能保证事务的原子性。在commit的时候会判断当前事务层次深度，如果为顶层，并且提交次数＋1等于事务次数（说明事务是安全完整的执行了），才真正提交到数据库。如果不完整，则在endTrnasaction的时候会回滚整个事务。</p><p>虽然这样能够实现事务操作，但是无法实现跨数据库操作，要实现跨数据库的事务估计只能用JTA了。</p><img src ="http://www.blogjava.net/foxty/aggbug/47481.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/foxty/" target="_blank">糊里糊涂</a> 2006-05-22 15:52 <a href="http://www.blogjava.net/foxty/archive/2006/05/22/47481.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于java的构造函数</title><link>http://www.blogjava.net/foxty/archive/2006/05/22/47479.html</link><dc:creator>糊里糊涂</dc:creator><author>糊里糊涂</author><pubDate>Mon, 22 May 2006 07:51:00 GMT</pubDate><guid>http://www.blogjava.net/foxty/archive/2006/05/22/47479.html</guid><wfw:comment>http://www.blogjava.net/foxty/comments/47479.html</wfw:comment><comments>http://www.blogjava.net/foxty/archive/2006/05/22/47479.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/foxty/comments/commentRss/47479.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/foxty/services/trackbacks/47479.html</trackback:ping><description><![CDATA[
		<p class="wpmd">今天在csdn上看到有人提出这样一个问题：</p>
		<div class="wpmd" style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 5px; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 5px; MARGIN: 5px 20px; BORDER-LEFT: #cccccc 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: #cccccc 1px solid">
				<p>1. class A {<br />2. A() { }<br />3. }<br />4.<br />5. class B extends A {<br />6. }<br />Which two statements are true? (Choose two)<br />A. Class B's constructor is public.<br />B. Class B's constructor has no arguments.<br />C. Class B's constructor includes a call to this().<br />D. Class B's constructor includes a call to super().</p>
				<p>个人认为A,B,D都是对的。为什么只有两个答案呢?</p>
		</div>
		<p class="wpmd">当时回答给他的答案是，默认类的构造函数是friendly的，所以A是错误的，但是又看了下楼主发布的测试代码</p>
		<div class="wpmd" style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 5px; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 5px; MARGIN: 5px 20px; BORDER-LEFT: #cccccc 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: #cccccc 1px solid">
				<p>很高兴大家的关注；<br />A.java<br />package packa;<br />class A<br />{</p>
				<p>}<br />B.java<br />package packb;<br />import packa.A;<br />class B<br />{<br />     public static void main(String[] args)<br />     {<br />         A a=new A();<br />     }<br />}<br />编译，运行是ok的。<br />可是把A类写成<br />class A<br />{<br />    A(){}<br />}<br />就会出现A() is not public in packa.A; cannot be accessed from outside package<br />的错误提示。<br />这不是说明默认的A类构造函数是public的吗？<br />希望大家继续帮忙解惑！</p>
		</div>
		<p class="wpmd">     当时直接看了这个代码，自己也没有考虑是否正确，就误认为是正确的，开始疑惑起来了。接着又做了下面的测试才发现真正的原因：</p>
		<div class="wpmd">
				<ul>
						<li> 类的默认构造函数（非手工实现）的访问权限是跟类的访问权限相关的，可以见下面的测试。</li>
				</ul>
		</div>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 5px; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 5px; MARGIN: 5px 20px; BORDER-LEFT: #cccccc 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: #cccccc 1px solid">
				<p>
						<font color="#aa0022">比如，一个类：</font>
				</p>
				<p>
						<font color="#aa0022">A{}</font>
				</p>
				<p>
						<font color="#aa0022">用javap进行反编译查看代码为：</font>
				</p>
				<p>
						<font color="#aa0022">class A extends java.lang.Object</font>
				</p>
				<p>
						<font color="#aa0022">{</font>
				</p>
				<p>
						<font color="#aa0022">    A(){}</font>
				</p>
				<p>
						<font color="#aa0022">}<br /></font>
				</p>
		</div>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 5px; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 5px; MARGIN: 5px 20px; BORDER-LEFT: #cccccc 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: #cccccc 1px solid">
				<p>
						<font color="#aa0022">如果写成 </font>
				</p>
				<p>
						<font color="#aa0022">public class A{}</font>
				</p>
				<p>
						<font color="#aa0022">反编译后为：</font>
				</p>
				<p>
						<font color="#aa0022">public class A extends java.lang.Object</font>
				</p>
				<p>
						<font color="#aa0022">{</font>
				</p>
				<p>
						<font color="#aa0022">  public A(){}</font>
				</p>
				<p>
						<font color="#aa0022">}</font>
				</p>
		</div>
<img src ="http://www.blogjava.net/foxty/aggbug/47479.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/foxty/" target="_blank">糊里糊涂</a> 2006-05-22 15:51 <a href="http://www.blogjava.net/foxty/archive/2006/05/22/47479.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>