Posted on 2006-01-13 11:34
呓语的博客 阅读(376)
评论(0) 编辑 收藏 所属分类:
Hibernate
http://forum.javaeye.com/viewtopic.php?p=17108&highlight=Serializable+generate+SessionImplementor+sessionImplementor%2C#17108
看了看。真是万分高兴,可能别人用了一个星期才解决的问题。我现在就可以不劳而获。惭愧啊。。
由于担心Hibernate自身提供的increment id generator有性能影响,我对increment进行了扩展,改为InMemoryIncrement:
InMemoryIncrement.java
代码:
//Declare Classes Import here,Do not use .* to import all the classes in package.
import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import java.util.Map;
import java.util.HashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.MappingException;
import net.sf.hibernate.dialect.Dialect;
import net.sf.hibernate.engine.SessionImplementor;
import net.sf.hibernate.type.Type;
import net.sf.hibernate.id.IdentifierGenerator;
import net.sf.hibernate.id.PersistentIdentifierGenerator;
import net.sf.hibernate.id.Configurable;
/**
* Hibernate high performence id generator extend IncrementGenerator.<br>
* This generator use ’select max(column) from table ’ to get id’s init value
* in first time.Then generate increment id in memory .
* <p>
* 原理:
* <li>使用long[]数组在内存中存储每个表的最大值,使用Map存储表名在数组中对应的索引值。
* <li>第一次访问某个表的id的最大值时会从数据库中取出并存放到long数组中,
* 同时在Map中保存索引值
* <li>第二次以后访问会首先从Map中读出索引值,根据索引值把long数组对应的值
* 加上递增步长并返回
* </p>
* @author fenghm
* @version $Revision$
*/
public final class InMemoryIncrement implements IdentifierGenerator, Configurable {
private static final Log log = LogFactory.getLog(InMemoryIncrement.class);
//存储最大值的数组的容量
private static final int MAX_CAPACITY = 200;
/**同步锁*/
private static final Object lock = new Object();
//存储表存储在数组中的索引值
private static Map map = new HashMap();
//递增步长,默认加1
private int step = 1;
//最大值数组
private static long[] seqs = new long[MAX_CAPACITY];
//最大值数组已经使用的容量
private static int lastIndex;
private String key;
private String sql;
private Connection connection;
private Class returnClass;
/**
* (none java doc)
* @see net.sf.hibernate.id.IdentifierGenerator#
* generate(net.sf.hibernate.engine.SessionImplementor, java.lang.Object)
*/
public Serializable generate(SessionImplementor session, Object object)
throws SQLException, HibernateException {
connection = session.connection();
long seq = -1;
//找到索引值
int index = findIndex();
//把最大值加1
seqs[index] = seqs[index] + step;
seq = seqs[index];
return new Long(seq);
}
/**
* 找到表中自动增长字段存储在数组中的索引值
* @return 索引值
*/
private int findIndex(){
int index = 0;
//首先中缓存中取出索引值
Integer integer = (Integer)map.get(key);
//如果没有找到就从数据库中读出最大值并进行cache
if(null == integer){
//double check lock
synchronized(lock){
integer = (Integer)map.get(key);
if(null == integer){
long maxvalue = 1;
try{
maxvalue = getMaxvalue();
}catch(SQLException e){
log.error(e);
}
integer = new Integer(lastIndex++);
seqs[integer.intvalue()] = maxvalue;
map.put(key,integer);
}
}
}
index = integer.intvalue();
return index;
}
/**
* (none java doc)
* @see net.sf.hibernate.id.Configurable#configure(net.sf.hibernate.type.Type,
* java.util.Properties, net.sf.hibernate.dialect.Dialect)
*/
public void configure(Type type, Properties params, Dialect d)
throws MappingException {
//取出table参数
String table = params.getProperty("table");
if (table == null){
table = params.getProperty(PersistentIdentifierGenerator.TABLE);
}
//取出column参数
String column = params.getProperty("column");
if (column == null){
column = params.getProperty(PersistentIdentifierGenerator.PK);
}
//表的sehcma参数
String schema = params.getProperty(PersistentIdentifierGenerator.SCHEMA);
returnClass = type.getReturnedClass();
//取出step参数
String stepvalue = params.getProperty("step");
if(null != stepvalue && !"".equals(stepvalue.trim())){
try{
step = Integer.parseInt(stepvalue);
}catch(Exception e){
log.error(e);
}
}
//构造存储在Map中的索引值的key name
key = table + "_$_" + column;
//根据参数构造取最大值的SQL
sql = "select max(" + column + ") from ";
if(null != schema){
sql += schema + ".";
}
sql += table;
}
/**
* 取指定表中id字段的最大值,不存在记录返回0
* @return 最大值
* @throws SQLException if sql error occurs.
*/
private long getMaxvalue() throws SQLException {
long maxvalue = 0;
PreparedStatement st = connection.prepareStatement(sql);
ResultSet rs = null;
try {
rs = st.executeQuery();
if(rs.next()) {
maxvalue = rs.getLong(1);
}
sql = null;
}finally {
if (rs != null){
rs.close();
}
st.close();
}
return maxvalue;
}
测试代码:
Data.java
代码:
public class Data {
private long id;
private String name;
private String email;
/**
* @return
*/
public String getEmail() {
return email;
}
/**
* @return
*/
public long getId() {
return id;
}
/**
* @return
*/
public String getName() {
return name;
}
/**
* @param string
*/
public void setEmail(String string) {
email = string;
}
/**
* @param l
*/
public void setId(long l) {
id = l;
}
/**
* @param string
*/
public void setName(String string) {
name = string;
}
}
Data.hbm.xml
代码:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping package="com.kmview.test.hibernate.model">
<class name="Data" table="data">
<id name="id" type="long" column="id">
<generator class="com.kmview.test.hibernate.Generator"/>
</id>
<property name="name" type="java.lang.String" length="20" column="name"/>
<property name="email" type="java.lang.String" column="email"/>
</class>
</hibernate-mapping>
ThreadMain.java
代码:
public class ThreadMain extends Thread {
public static void main(String[] args) {
try{
Configuration cfg = new Configuration().configure();
SchemaExport schema = new SchemaExport(cfg);
schema.create(false,true);
for(int i=0;i<100;i++){
new ThreadMain().start();
}
}catch(Exception e){
e.printStackTrace();
}
}
public void run(){
try{
for(int i=0;i<20;i++){
Session session = HibernateSession.openSession();
Data data = new Data();
data.setName("sdfsfsdf");
data.setEmail("sdflkas;lfdalsfjasljf@d.d");
session.save(data);
session.flush();
HibernateSession.closeSession();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
HibernateSession.java
代码:
public final class HibernateSession {
private HibernateSession(){}
//synchronized lock for getSessionFactory
private static Object lock = new Object();
//common log object
private static Log log = LogFactory.getLog(HibernateSession.class);
//Hibernate SessionFactory
private static SessionFactory sessionFactory;
//Implement Hibatenate ThreadLocal pattern
private static final ThreadLocal session = new ThreadLocal();
/**
* 自动在ClassPath的根路径寻找hibernate.properties与hibernate.cfg.xml文件<br>
* 并初始化SessionFactory
* @return SessionFactory
*/
private static SessionFactory buildSessionFactory(){
SessionFactory factory = null;
try{
Configuration config = new Configuration();
config = config.configure();
factory = config.buildSessionFactory();
log.info("ok,SessionFactory builded!");
}catch(HibernateException e){
log.error(e);
}
return factory;
}
/**
* 取得当前会话的Hibernae Session对象,并打开数据库连接
* @return Hibernate Session Object for Data Access
* @exception HibernateException throw HibernateException
*/
public static Session openSession() throws HibernateException{
Session s = (Session)session.get();
if(null == s){
getSessionFactory();
if(null != sessionFactory){
s = sessionFactory.openSession();
session.set(s);
}else{
log.error("Error,SessionFactory object is not inited!");
}
}else if(!s.isConnected()){
s.reconnect();
}
return s;
}
/**
* 关闭数据库连接,在每次Session用完的时候,应该马上调用closeSession,<br>
* 以把数据库连接归还到数据库连接池中,提高并发性能。
*/
public static void closeSession(){
try{
Session s = (Session)session.get();
if(null != s && s.isConnected()){
s.disconnect();
}
}catch(HibernateException e ){
log.error(e);
}
}
/**
* 释放Hibernate Session对象,此方法应该在当前线程消亡之前调用。<br>
* 例如:在Web应用中可以使用filter统一在最后进行调用<br>
* <code><pre>
* public class HibernateFilter extends HttpServlet implements Filter{
* private FilterConfig filterConfig;
* public void init(FilterConfig filterConfig){
* this.filterConfig = filterConfig;
* }
*
* public void doFilter(ServletRequest request,ServletResponse response,
* FilterChain filterChain){
* try{
* filterChain.doFilter(request,response);
* } catch(ServletException sx){
* filterConfig.getServletContext().log(sx.getMessage());
* } catch(IOException iox){
* filterConfig.getServletContext().log(iox.getMessage());
* }finally{
* HibernateSession.releaseSession();
* }
* }
* }
* </pre></code>
* 在Hibernate的API文档提到,Session的close()方法不是必须要被调用的,<br>
* 但disconnect()方法是必须的;所以此方法也不是必须要被调用的,但是<br>
* closeSession()方法是必须的。
* @exception HibernateException throw HibernateException
*/
public static void releaseSession() throws HibernateException{
Session s = (Session)session.get();
session.set(null);
if(null != s){
s.close();
}
}
/**
* 设置SessionFactory,提供此方法是为了可以在外部初始化SessionFactory.
* @param factory SessionFactory
*/
public static void setSessionFactory(SessionFactory factory){
if(null == sessionFactory){
sessionFactory = factory;
}
}
/**
* 获取SessionFactory,第一次访问时会自动在ClassPath的根路径寻找<br>
* hibernate.properties与hibernate.cfg.xml文件并初始化。
* @return SessionFactory
*/
public static SessionFactory getSessionFactory(){
//Double check lock.
if(null == sessionFactory){
synchronized(lock){
if(null == sessionFactory){
sessionFactory = buildSessionFactory();
}
}
}
return sessionFactory;
}
}