(点击上方公众号,可快速关注)
来源:袁鸣凯 ,
blog.csdn.net/lifetragedy/article/details/7751059
2.6.8 ClassRoomDAOImpl类
package sky.org.dao.impl;
import java.sql.*;
import java.util.*;
import sky.org.dao.ClassRoomDAO;
import sky.org.util.db.ConnectionManager;
public class ClassRoomDAOImpl implements ClassRoomDAO {
public void addStudentClassRoom(String roomId, String sNo) throws Exception {
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = ConnectionManager.getConnection();
pstmt = conn
.prepareStatement(ClassRoomDAOSql.ADD_STUDENT_CLASSROOM);
pstmt.setString(1, roomId);
pstmt.setString(2, sNo);
pstmt.executeUpdate();
} catch (Exception e) {
throw new Exception("addStudentClassRoom:" + e.getMessage(), e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
pstmt = null;
}
} catch (Exception e) {
}
}
}
}
2.6.9 StudentDAO接口
package sky.org.dao;
import java.util.*;
import sky.org.bean.Student;
public interface StudentDAO {
public void addStudent(Student std) throws Exception;
}
2.6.10 StudentDAOImpl类
package sky.org.dao.impl;
import java.sql.*;
import javax.sql.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import sky.org.bean.Student;
import sky.org.dao.StudentDAO;
import sky.org.util.db.ConnectionManager;
import java.util.List;
import java.util.ArrayList;
import java.util.Vector;
import java.text.*;
import sky.org.util.StringUtil;
public class StudentDAOImpl implements StudentDAO {
private Log logger = LogFactory.getLog(this.getClass());
public void addStudent(Student std) throws Exception {
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = ConnectionManager.getConnection();
pstmt = conn.prepareStatement(StudentDAOSql.ADD_STUDENT);
pstmt.setString(1, std.getsNo());
pstmt.setString(2, std.getsName());
pstmt.setString(3, std.getsAge());
pstmt.setString(4, std.getGender());
pstmt.setDate(5, StringUtil.convertStrToDate(std.getSbirth()));
pstmt.executeUpdate();
} catch (Exception e) {
throw new Exception("addStudent:" + e.getMessage(), e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
pstmt = null;
}
} catch (Exception e) {
}
}
}
public void delStudent(String sNo) throws Exception {
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = ConnectionManager.getConnection();
pstmt = conn.prepareStatement(StudentDAOSql.DEL_STUDENT);
pstmt.setString(1, sNo);
pstmt.executeUpdate();
} catch (Exception e) {
throw new Exception("delStudent:" + e.getMessage(), e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
pstmt = null;
}
} catch (Exception e) {
}
}
}
}
2.6.11 StudentDAOSql类
package sky.org.dao.impl;
public class StudentDAOSql {
public final static String ADD_STUDENT = "insert into t_student(sno, sname, sage, gender,
sbirth)values(?,?,?,?,?)";
}
2.6.12 ClassRoomDAOSql类
package sky.org.dao.impl;
public class ClassRoomDAOSql {
public static String ADD_STUDENT_CLASSROOM = "insert into
t_student_classroom(room_id,sno)values(?,?)";
}
2.6.13 ClassRoom 类
package sky.org.bean;
import java.io.*;
public class ClassRoom implements Serializable {
private String roomId = "";
private String roomName = "";
public String getRoomId() {
return roomId;
}
public void setRoomId(String roomId) {
this.roomId = roomId;
}
public String getRoomName() {
return roomName;
}
public void setRoomName(String roomName) {
this.roomName = roomName;
}
}
2.6.14 Student类
package sky.org.bean;
import java.io.*;
public class Student implements Serializable {
public String getsNo() {
return sNo;
}
public void setsNo(String sNo) {
this.sNo = sNo;
}
public String getsName() {
return sName;
}
public void setsName(String sName) {
this.sName = sName;
}
public String getsAge() {
return sAge;
}
public void setsAge(String sAge) {
this.sAge = sAge;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
private String sNo = "";
private String sName = "";
private String sAge = "";
private String gender = "";
private String sbirth = "";
private String classRoomId = "";
private String classRoomName = "";
public String getClassRoomId() {
return classRoomId;
}
public void setClassRoomId(String classRoomId) {
this.classRoomId = classRoomId;
}
public String getClassRoomName() {
return classRoomName;
}
public void setClassRoomName(String classRoomName) {
this.classRoomName = classRoomName;
}
public String getSbirth() {
return sbirth;
}
public void setSbirth(String sbirth) {
this.sbirth = sbirth;
}
}
2.6.15 StudentCRUD类(运行主类)
package sky.org.test;
import sky.org.bean.Student;
import sky.org.service.StudentService;
import sky.org.service.impl.StudentServiceImpl;
public class StudentCRUD {
public void addStudent() throws Exception {
StudentService stdService = new StudentServiceImpl();
Student std = new Student();
std.setsNo("101");
std.setsName("abc");
std.setSbirth("1977/01/01");
std.setsAge("35");
std.setGender("m");
std.setClassRoomId("1");
std.setClassRoomName("class1");
stdService.addStudent(std);
}
public static void main(String[] args) {
StudentCRUD testStudentCRUD = new StudentCRUD();
try {
testStudentCRUD.addStudent();
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
}
}
三、Hibernate里的ThreadLocal
Hibernate在事务操作中也支持ThreadLocal的作法,我们这边指的是不用Spring去做代理,而直接用Hibernate。即:
Service Method{
hbDAO1.doSomething();
hbDAO2.doSomething();
hbDAO3.doSomething();
。。。
}
Hibernate版本3后增加了新特性,即getCurrentSession()。
3.1 getCurrentSession与openSession的区别
3.1.1 openSession
我们传统的做法是openSession即:
public void testUser() throws Exception {
Transaction tran = null;
SessionFactory factory = null;
UserDAO userDAO = new UserDAOImpl();
try {
factory = HibernateUtil.getInstance().getSessionFactory();
Session session = factory.openSession();
tran = session.beginTransaction();
TUser testUser = new TUser();
testUser.setId(new Integer(i));
testUser.setName("abc");
userDAO.addUser(testUser);
tran.commit();
} catch (Exception e) {
tran.rollback();
throw new Exception(e);
} finally {
try{
if(session!=null){
session.close();
session=null();
}
}catch(Excepton e){}
}
}
这样做,能够保证我们每次在finally块中正确关闭session,但是,如果我们也遇上了这样的case即:
Service Method{
hbDAO1.doSomething();
hbDAO2.doSomething();
hbDAO3.doSomething();
。。。
}
这时,我们如果用的是openSession,应该怎么办?
解决方案一:
自己用ThreadLocal模式写一个SessionManagement类,来维护这个session。
解决方案二:
把在Service方法中打开的session,传到每个dao方法中,使每个dao方法使用同一个session,最后在Service方法中去关闭它(很烂的做法)。
下面我们来看看Hibernate自身提供的getCurrentSession()的做法吧
3.1.2 getCurrentSession
要使用这个getCurrentSession,你的hibernate的设置必须如下(红色加粗部分显示-就喜欢粗J):
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.url">
jdbc:oracle:thin:@localhost:1521:myorcl
</property>
<property name="dialect">
org.hibernate.dialect.Oracle9Dialect
</property>
<property name="connection.username">abc</property>
<property name="connection.password">abc</property>
<property name="connection.driver_class">
oracle.jdbc.OracleDriver
</property>
<property name="show_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<property name="hibernate.current_session_context_class">thread</property>
<mapping resource="com/cts/testhb/model/TUser.hbm.xml" />
</session-factory>
</hibernate-configuration>
然后上述代码将变成如下的样子:
public void testUser() throws Exception {
Transaction tran = null;
SessionFactory factory = null;
UserDAO userDAO = new UserDAOImpl();
try {
factory = HibernateUtil.getInstance().getSessionFactory();
Session session = factory.getCurrentSession();
tran = session.beginTransaction();
for (int i = 0; i < 100; i++) {
TUser testUser = new TUser();
testUser.setId(new Integer(i));
testUser.setName("abc");
userDAO.addUser(testUser);
}
tran.commit();
} catch (Exception e) {
tran.rollback();
throw new Exception(e);
} finally {
ThreadLocalSessionContext.unbind(factory);
}
}
而你的每个DAO方法中的代码是这样实现的:
public void addUser(TUser user) throws Exception {
SessionFactory factory = HibernateUtil.getInstance()
.getSessionFactory();
Session session = factory.getCurrentSession();
session.save(user);
}
是不是很方便的哈。
3.1.3 openSession与getCurrentSession的区别
严重注意下面几点:
openSession一旦被调用,必须且一定要在finally块中close,要不然你就等着out of memory吧;
如果你使用的是getCurrentSession,那么你不能在finally块中调用”session.close()”,不行你可以在finally块中用try-catch把session.close();包起来,然后在catch{}块中抛出这个exception,这个exception将会是:sessionhas been already closed。
因为:
l 如果你用的是getCurrentSession,那么它在session.commit()或者是session.rollback()时就已经调用了一次session.close()了,因此你只要正确放置session.commit()与rollback()即可。
l 你必须在finally块中调用”ThreadLocalSessionContext.unbind(factory);”,以使得当前的事务结束时把session(即dbconnection)还回db connection pool中
如果你使用的是getCurrentSession,那么就算你是一个简单的select语句,也必须包含在:
tran = session.beginTransaction();
//your select hibernate query
tran.commit();
这样的事务块中,要不然它将会抛出这样的一个错误:
NoHibernate Session bound to thread, and configuration does not allow creation ofnon-transactional
看下面的例子:
try {
factory = HibernateUtil.getInstance().getSessionFactory();
Session session = factory.getCurrentSession();
tran = session.beginTransaction();
TUser testUser = userDAO.getUserByID("1");
log.info("user id===="+testUser.getId()+" user name===="+testUser.getName());
tran.commit();
} catch (Exception e) {
tran.rollback();
throw new Exception(e);
} finally {
ThreadLocalSessionContext.unbind(factory);
}
可以看到我们的查询是被tran=session.beginTransaction一直到tran.commit()或者是tran.rollback()结束的,如果,你把你的hibernate查询移到了tran=session.beginTransaction的上面。。。就会抛上述这个错误。
3.1.4 getCurrentSession带来的问题
getCurrentSession非常好,不需要我们自己写ThreadLocal只需要在hibernate.cfg的配置文件中声音一下就可以获得ThreadLocal的好处,便于我们划分我们的程序的层次与封装,带也带来了一定的性能问题。
特别是“如果你使用的是getCurrentSession,那么就算你是一个简单的select语句,也必须包含在事务块中”。这给我们带来了很大的问题。
因此,本人建议,在碰到如果:
一个service方法中只有单个dao操作且此操作是一个select类的操作,请使用openSession,并且即时在finally块中关闭它;
如果一个service方法中涉及到多个dao操作,请一定使用getCurrentSession;
如果一个service方法中混合着select操作,delete, update, insert操作。请按照下述原则:
将属于select的操作,单独做成一个dao方法,该dao使用openSession并且在finally块中及时关闭session,该dao只需要返回一个java的object如:List<Student>即可,如果出错将exception抛回给调用它的service方法。
对于其它的delete, insert, update的dao操作,请使用getCurrentSession。
忌讳,把select类的操作放在“事务”中。
系列
看完本文有收获?请转发分享给更多人
关注「ImportNew」,提升Java技能