呓语的博客

不管前面的路有多艰辛多长,只要怀着一颗执着的心。成功就离你不远了!
posts - 43, comments - 2, trackbacks - 0, articles - 1

自定义主键

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;
    }
}


只有注册用户登录后才能发表评论。


网站导航: