1. 程式人生 > >高併發下的基礎優化(三)——訂單主鍵(終)

高併發下的基礎優化(三)——訂單主鍵(終)

具體不說了,看上一篇。

開發框架spring4.2.9-springmvc-hibernate4.3.11Final,需要包的可以在我的資源裡找。

由於這些類都要封裝進dao基類中,所以就不交給spring管理了,註解都去掉。

方便大家參考依賴,保留import,看別人的程式碼不貼上依賴,那麼多同名的包,誰知道要用哪個。

import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import …….util.localcache.LocalCacheUtil;
/**
 * 主鍵生成基類
 * @author 瘋狂的蚯蚓
 *
 */
public class IdGenerator
{
	/**
     * AtomicInteger是一個提供原子操作的Integer類,通過執行緒安全的方式操作加減。
     */
    protected AtomicInteger value; 
	
    protected String time;  
    
    /**
     * 讀寫鎖
     */
    protected ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); 
    
    public String getSplitString() 
	{  
        return "";  
    }  
  
    public int getInitial() 
    {  
        return 0;  
    }  
  
    public String getPrefix() 
    {  
    	String result = null;
    	try 
    	{
    		//查詢伺服器的配置檔案
			result = (String)LocalCacheUtil.query(PropertiesFileIOUtil.MECHINE_CODE_KEY);
			if(result==null)
			{
				Map<String, String> map = PropertiesFileIOUtil.loadProps();
				if(map==null || !map.containsKey(PropertiesFileIOUtil.MECHINE_CODE_KEY))
				{
					return "";
				}
				//伺服器號
				result = map.get(PropertiesFileIOUtil.MECHINE_CODE_KEY);
				//加入本地快取
				LocalCacheUtil.put(PropertiesFileIOUtil.MECHINE_CODE_KEY, result);
			}
		} 
    	catch (Exception e) 
    	{
    		e.printStackTrace();
    		throw new RuntimeException("獲取主鍵字首失敗");
		}
        return result;  
    }  
  
    public int getRollingInterval() 
    {  
        return 1;  
    }  
}
/**
 * Id生成器配置介面
 * @author 瘋狂的蚯蚓
 *
 */
public interface IdGeneratorConfig {
	 /** 
     * 獲取分隔符 
     * @return 
     */  
    String getSplitString();  
      
    /** 
     * 獲取初始值 
     * @return 
     */  
    int getInitial();   
      
    /** 
     * 獲取ID字首 
     * @return 
     */  
    String getPrefix();  
      
    /** 
     * 獲取滾動間隔, 單位: 秒 
     * @return 
     */  
    int getRollingInterval();  
}

import java.util.Map;

import …….util.localcache.LocalCacheUtil;

/**
 * 主鍵生成配置實現類
 * @author 瘋狂的蚯蚓
 *
 */
public class DefaultIdGeneratorConfig implements IdGeneratorConfig 
{
	@Override  
    public String getSplitString() 
	{  
        return "";  
    }  
  
    @Override  
    public int getInitial() 
    {  
        return 1;  
    }  
  
    @Override  
    public String getPrefix() 
    {  
    	String result = null;
    	try 
    	{
    		//查詢伺服器的配置檔案
			result = (String)LocalCacheUtil.query(PropertiesFileIOUtil.MECHINE_CODE_KEY);
			if(result==null)
			{
				Map<String, String> map = PropertiesFileIOUtil.loadProps();
				if(map==null || !map.containsKey(PropertiesFileIOUtil.MECHINE_CODE_KEY))
				{
					return "";
				}
				//伺服器號
				result = map.get(PropertiesFileIOUtil.MECHINE_CODE_KEY);
				//加入本地快取
				LocalCacheUtil.put(PropertiesFileIOUtil.MECHINE_CODE_KEY, result);
			}
		} 
    	catch (Exception e) 
    	{
    		e.printStackTrace();
    		throw new RuntimeException("獲取主鍵字首失敗");
		}
        return result;  
    }  
  
    @Override  
    public int getRollingInterval() 
    {  
        return 1;  
    }  
}

快取啥的就自己去研究了,很簡單,沒幾行程式碼,以下是配置檔案的讀取,當然其他方法都行,不一定要存檔案

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * 讀取配置檔案工具類
 * @author 瘋狂的蚯蚓
 *
 */
public class PropertiesFileIOUtil 
{
	/**
	 * 機器號程式碼
	 */
	public static final String MECHINE_CODE_KEY = "MechineCode"; 
	
	public static Properties props; 
	
	public static Map<String, String> loadProps()
	{  
		
		Map<String, String> result = new HashMap<String, String>();
        props = new Properties();  
        InputStream in = null;  
        try 
        {  
            //第一種,通過類載入器進行獲取properties檔案流  
            //in = PropertyUtil.class.getClassLoader().getResourceAsStream("sysConfig.properties");  
            //第二種,通過類進行獲取properties檔案流  
            in = PropertiesFileIOUtil.class.getClassLoader().getResourceAsStream("config/mechineCode.properties");  
            props.load(in);  
            
            String mechineCode = props.getProperty(MECHINE_CODE_KEY);
//          System.out.println("mechineCode="+mechineCode);
            result.put(MECHINE_CODE_KEY, mechineCode);
        } 
        catch (FileNotFoundException e) 
        {  
        	e.printStackTrace();
            //logger.error("sysConfig.properties檔案未找到");  
        } 
        catch (IOException e) 
        {  
        	e.printStackTrace();
            //logger.error("出現IOException");  
        } 
        finally 
        {  
            try 
            {  
                if(null != in) 
                {  
                    in.close();  
                }  
            } 
            catch (IOException e) 
            {  
                //logger.error("sysConfig.properties檔案流關閉出現異常");  
            }  
        }  
        //logger.info("載入properties檔案內容完成...........");  
        //logger.info("properties檔案內容:" + props);  
        return result;
    }  
	
	public String getProperty(String key)
	{  
        if(null == props) 
        {  
            loadProps();  
        }  
        return props.getProperty(key);  
    }  
  
    public String getProperty(String key, String defaultValue) 
    {  
        if(null == props) 
        {  
            loadProps();  
        }  
        return props.getProperty(key, defaultValue);  
    }  
    
}

以下是dao基類介面

import java.io.Serializable;
import java.util.List;

import …….vo.ComboBox;
import …….vo.Pagination;

/**
 * 通用Dao介面
 * 
 * @param <T>  實體物件類
 * @param <PK> 主鍵
 */
public interface GenericDao<T, PK extends Serializable> {
	
	/**
	 * 根據主鍵獲得一個實體物件
	 * 
	 * @param id
	 * @return
	 */
	public T findById(PK id);

	/**
	 * 獲得表中的所有實體物件
	 * 
	 * @return
	 */
	public List<T> findAll();

	/**
	 * 新增一個實體物件
	 * 
	 * @param entity
	 * @return
	 */
	public T save(T entity);

	/**
	 * 更新一個實體物件
	 * 
	 * @param entity
	 */
	public void update(T entity);

	/**
	 * 刪除一個實體物件
	 * 
	 * @param entity
	 */
	public void delete(T entity);

	/**
	 * 根據HQL語句和查詢條件,獲得具體數量
	 * 
	 * @param hql  不需要也不能寫select count(*),直接從from開始寫
	 * @param params
	 * @return
	 */
	public Long countByHQL(String hql, Object[] params);

	/**
	 * 根據HQL語句和查詢條件,獲得一個實體物件
	 * 
	 * @param hql
	 * @param params
	 * @return
	 */
	public T getEntityByHQL(String hql, Object[] params);

	/**
	 * 根據HQL語句和查詢條件,獲得多個實體物件
	 * 
	 * @param hql
	 * @param params
	 * @return
	 */
	public List<T> listEntityByHQL(String hql, Object[] params);

	/**
	 * 根據HQL語句和查詢條件,獲得多個實體物件,分頁顯示,可排序
	 * 
	 * @param hql
	 *            必須是查詢整個model類的資訊,不能只查詢部分欄位 正確寫法:from 類名 where 條件 order by
	 *            錯誤寫法:select 表名(欄位名) from 類名 where 條件
	 * @param params
	 * @param pageSize
	 *            每頁顯示記錄數
	 * @param pageNumber
	 *            當前第幾頁
	 * @return
	 */
	public Pagination listEntityByHQL(String hql, Object[] params,Integer pageSize, Integer pageNumber);
     
	
	public Pagination listEntityByHQL1(String hql, Object[] params,
			Integer pageSize, Integer pageNumber);
	
	public Pagination listEntityByHQLbox(String hql, Object[] params,
			Integer pageSize, Integer pageNumber);
	
	
	/**
	 * 根據SQL語句和查詢條件,獲得多個實體物件,分頁顯示,可排序
	 * 
	 * @param sql
	 * @param params
	 * @param pageSize
	 *            每頁顯示記錄數
	 * @param pageNumber
	 *            當前第幾頁
	 * @return
	 */
	public Pagination listEntityBySQL(String sql, Object[] params,Integer pageSize, Integer pageNumber);
	
	/**
	 * 執行刪除或者更新的HQL語句
	 * 
	 * @param hql
	 * @param params
	 * @return
	 */
	public Integer updateByHQL(String hql, Object[] params);
	
	/**
	 * 執行刪除或者更新的SQL語句
	 * 
	 * @param sql
	 * @param params
	 * @return
	 */
	public Integer updateBySQL(String sql, Object[] params);
	
	/**
	 * 根據任意的select語句,獲得對應列的物件陣列
	 * @param hql
	 * @param params
	 * @return
	 */
	public List<Object[]> listEntityBySelect(String hql, Object[] params);
	
	/**
	 * 根據HQL語句和查詢條件,獲得實體物件中一個欄位的所有值的集合
	 * @param hql
	 * @param params
	 * @return	easyui-combobox格式的vo類
	 */
	public List<ComboBox> listFieldByHQL(String hql, Object[] params);
	
	/**
	 * 通過sql語句,查詢結果對映成實體
	 * @param sql
	 * @param c 結果要對映的實體物件
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	List listEntityBySql(String sql,Class c);
	
	/**
	 * 獲取下一個主鍵,預設是從1開始遞增,如果有特殊需求需要在dao實現中重寫該方法
	 * @return
	 */
	public String next();
}
主鍵生成方法在該類的最底部,還有不完善的大家直接去修修補補,優化提升
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import javax.annotation.Resource;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.springframework.orm.hibernate4.HibernateCallback;
import org.springframework.orm.hibernate4.HibernateTemplate;

import …….dao.GenericDao;
import …….idgenerator.IdGenerator;
import …….vo.ComboBox;
import …….vo.Pagination;

public class GenericDaoHibernate<T, PK extends Serializable> extends IdGenerator
	implements GenericDao<T, PK> ,Runnable 
{

	private final Class<T> clazz;
	protected HibernateTemplate hibernateTemplate;

	@SuppressWarnings("unchecked")
	public GenericDaoHibernate() {
		clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        value = new AtomicInteger(getInitial());  
	}

	public HibernateTemplate getHibernateTemplate() {
		return hibernateTemplate;
	}
	@Resource()
	public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
		this.hibernateTemplate = hibernateTemplate;
	}

	@Override
	public T findById(PK id) {
		return this.hibernateTemplate.get(clazz, id);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> findAll() {
		return (List<T>) this.hibernateTemplate.find("from " + clazz.getName());
	}

	@Override
	public T save(T entity) {
		this.hibernateTemplate.persist(entity);
		return entity;
	}

	@Override
	public void update(T entity) {
		this.hibernateTemplate.merge(entity);
	}

	@Override
	public void delete(T entity) {
		this.hibernateTemplate.delete(entity);
	}

	/**
	 * 根據HQL語句和查詢條件,獲得一個物件
	 * 例:分頁時查詢出總的記錄數
	 * 
	 * @param hql
	 * @param params
	 * @return
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private Object queryObjectByHQL(final String hql, final Object[] params) {
		Object obj = this.hibernateTemplate.execute(new HibernateCallback() {
			@Override
			public Object doInHibernate(Session session) throws HibernateException {
				Query query = session.createQuery(hql);
				if (params != null) {
					for (int i = 0; i < params.length; i++) {
						query.setParameter(i, params[i]);
					}
				}
				return query.uniqueResult();
			}
		});
		return obj;
	}
	/**
	 * 根據SQL語句和查詢條件,獲得一個物件
	 * 例:分頁時查詢出總的記錄數
	 * 
	 * @param hql
	 * @param params
	 * @return
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private Object queryObjectBySQL(final String sql, final Object[] params) {
		Object obj = this.hibernateTemplate.execute(new HibernateCallback() {
			@Override
			public Object doInHibernate(Session session) throws HibernateException {
				Query query = session.createSQLQuery(sql);
				if (params != null) {
					for (int i = 0; i < params.length; i++) {
						query.setParameter(i, params[i]);
					}
				}
				return query.uniqueResult();
			}
		});
		return obj;
	}
	
	@Override
	public Long countByHQL(String hql, Object[] params) {
		// 拼接成新的hql字串,用於查詢總共多少條資料, 如果有order by要擷取掉,因為有的資料庫不支援
		String nhql = "select count(*) " + hql.split(" order by")[0];
		return (Long) this.queryObjectByHQL(nhql, params); // 獲得總的記錄數
	}
	public Long countBySQL(String sql, Object[] params) {
		// 拼接成新的hql字串,用於查詢總共多少條資料, 如果有order by要擷取掉,因為有的資料庫不支援
		String nhql = "select count(*) from (" + sql.split(" order by")[0] + ")";
		/*
		 * 獲得總的記錄數
		 * Hibernate 執行SQL語句的count函式返回型別
		 * oracle :BigDecimal
		 * db2 : Integer
		 */
		Object obj = this.queryObjectBySQL(nhql, params);
		String objName = obj.getClass().getName();
		if("java.math.BigDecimal".equals(objName)) {
			BigDecimal bq = (BigDecimal) obj;
			return bq.longValue();  
		}else if("java.lang.Integer".equals(objName)){
			Integer bq = (Integer) this.queryObjectBySQL(nhql, params);
			return bq.longValue();  
		}else {
			return 0L;
		}
	}
	
	
	@Override
	public T getEntityByHQL(String hql, Object[] params) 
	{
		@SuppressWarnings("unchecked")
		List<T> list = (List<T>) this.hibernateTemplate.find(hql, params);
		
		if (list != null && list.size() > 0)
		{
			return list.get(0);
		} 
		else 
		{
			return null;
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> listEntityByHQL(String hql, Object[] params) 
	{
		return (List<T>) this.hibernateTemplate.find(hql, params);
	}

	/**
	 * 分頁查詢
	 * 
	 * @param hql
	 * @param params
	 * @param pageSize
	 * @param pageNumber
	 * @param totalCount
	 * @return
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private Pagination getPaginationByHQL(final String hql, final Object[] params, final Integer pageSize, 
								final Integer pageNumber, final Long totalCount) {
		return (Pagination) this.hibernateTemplate.execute(new HibernateCallback() {
			@Override
			public Object doInHibernate(Session session) throws HibernateException {
				Pagination pagination = new Pagination(pageSize, pageNumber, totalCount);
				Query query = session.createQuery(hql);
				if (params != null) {
					for (int i = 0; i < params.length; i++) {
						query.setParameter(i, params[i]);
					}
				}
				query.setFirstResult(pageSize * (pageNumber - 1));
				query.setMaxResults(pageSize);
				pagination.setList(query.list());
				return pagination;
			}
		});
	}
	/**
	 * 分頁查詢
	 * 
	 * @param sql
	 * @param params
	 * @param pageSize
	 * @param pageNumber
	 * @param totalCount
	 * @return
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private Pagination getPaginationBySQL(final String sql, final Object[] params, final Integer pageSize, 
								final Integer pageNumber, final Long totalCount) {
		return (Pagination) this.hibernateTemplate.execute(new HibernateCallback() {
			@Override
			public Object doInHibernate(Session session) throws HibernateException {
				Pagination pagination = new Pagination(pageSize, pageNumber, totalCount);
				Query query = session.createSQLQuery(sql);
				if (params != null) {
					for (int i = 0; i < params.length; i++) {
						query.setParameter(i, params[i]);
					}
				}
				query.setFirstResult(pageSize * (pageNumber - 1));
				query.setMaxResults(pageSize);
				pagination.setList(query.list());
				return pagination;
			}
		});
	}
	
	@Override
	public Pagination listEntityByHQL(String hql, Object[] params, Integer pageSize, Integer pageNumber) {
		long totalCount = this.countByHQL(hql, params);
		return this.getPaginationByHQL(hql, params, pageSize, pageNumber, totalCount);
	}
	@Override
	public Pagination listEntityBySQL(String hql, Object[] params, Integer pageSize, Integer pageNumber) {
		long totalCount = this.countBySQL(hql, params);
		return this.getPaginationBySQL(hql, params, pageSize, pageNumber, totalCount);
		
	}
	@Override
	public Pagination listEntityByHQL1(String hql, Object[] params, Integer pageSize, Integer pageNumber) {
		String nhql = "select count(*) from (select distinct ij.docserialnum,ir.docname,ir.scanuser,ir.orgcode,ir.cartonno,ir.boxno,to_char(ir.scantime, 'yyyy-mm-dd hh24:mi:ss'),count(ir.docname) " + hql.substring((hql.split("from")[0].length()-1)<0?0:(hql.split("from")[0].length()-1), hql.length()-1).split(" order by")[0]+")";
		Integer totalCount = Integer.parseInt(this.queryObject1(nhql, params).toString());
		return this.getPagination1(hql, params, pageSize, pageNumber, totalCount);
	}
	
	@Override
	public Pagination listEntityByHQLbox(String hql, Object[] params, Integer pageSize, Integer pageNumber) {
		String nhql = "select count(*) from (select distinct ij.docserialnum,to_char(ij.creationtime, 'yyyy-mm-dd hh24:mi:ss'),ij.maindocname,ir.scanuser,ir.orgcode,ir.cartonno,ir.boxno,count(ir.docname) " + hql.substring((hql.split("from")[0].length()-1)<0?0:(hql.split("from")[0].length()-1), hql.length()-1).split(" order by")[0]+")";
		Integer totalCount = Integer.parseInt(this.queryObject1(nhql, params).toString());
		return this.getPagination1(hql, params, pageSize, pageNumber, totalCount);
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public Object queryObject1(final String hql, final Object[] params) {
		Object obj = this.hibernateTemplate.execute(new HibernateCallback() {
			@Override
			public Object doInHibernate(Session session) throws HibernateException {
				Query query = session.createSQLQuery(hql);
				if (params != null) {
					for (int i = 0; i < params.length; i++) {
						query.setParameter(i, params[i]);
					}
				}
				return query.uniqueResult();
			}
		});
		return obj;
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public Pagination getPagination1(final String hql, final Object[] params, final Integer pageSize, final Integer pageNumber, final Integer totalCount) {
		return (Pagination) this.hibernateTemplate.execute(new HibernateCallback() {
			@Override
			public Object doInHibernate(Session session) throws HibernateException {
				Pagination pagination = new Pagination(pageSize, pageNumber, totalCount);
				Query query = session.createSQLQuery(hql);
				if (params != null) {
					for (int i = 0; i < params.length; i++) {
						query.setParameter(i, params[i]);
					}
				}
				query.setFirstResult(pageSize * (pageNumber - 1));
				query.setMaxResults(pageSize);
				pagination.setList(query.list());
				return pagination;
			}
		});
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private Integer updateEntity(final String hql, final Object[] params) {
		Integer i = (Integer) this.hibernateTemplate.execute(new HibernateCallback() {
			@Override
			public Object doInHibernate(Session session) throws HibernateException {
				Query query = session.createQuery(hql);
				if (params != null) {
					for (int i = 0; i < params.length; i++) {
						query.setParameter(i, params[i]);
					}
				}
				Integer count = query.executeUpdate();
				return count;
			}
		});
		return i;
	}
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private Integer updateEntityBySQL(final String sql, final Object[] params) {
		Integer i = (Integer) this.hibernateTemplate.execute(new HibernateCallback() {
			@Override
			public Object doInHibernate(Session session) throws HibernateException {
				Query query = session.createSQLQuery(sql);
				if (params != null) {
					for (int i = 0; i < params.length; i++) {
						query.setParameter(i, params[i]);
					}
				}
				Integer count = query.executeUpdate();
				return count;
			}
		});
		return i;
	}

	@Override
	public Integer updateByHQL(String hql, Object[] params) {
		return updateEntity(hql, params);
	}
	
	@Override
	public Integer updateBySQL(String sql, Object[] params) {
		return updateEntityBySQL(sql, params);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Object[]> listEntityBySelect(String hql, Object[] params) {
		return (List<Object[]>) this.hibernateTemplate.find(hql, params);
	}

	@Override
	public List<ComboBox> listFieldByHQL(String hql, Object[] params) {
		@SuppressWarnings("unchecked")
		List<String> objects = (List<String>) hibernateTemplate.find(hql, params);
		List<ComboBox> lists = new ArrayList<ComboBox>();
		for (String  obj: objects) {
			ComboBox cb = new ComboBox();
			cb.setText(obj);
			cb.setValue(obj);
			lists.add(cb);
		}
		return lists;
	}

	@SuppressWarnings("rawtypes")
	@Override
	public List listEntityBySql(String sql, Class c) {
		SQLQuery query=hibernateTemplate.getSessionFactory().getCurrentSession().createSQLQuery(sql).addEntity(c);
		return query.list();
	}

	
	@Override
	public void run() 
	{
		while (true)
		{  
            try 
            {  
                Thread.sleep(1000 * getRollingInterval());  
            } 
            catch (InterruptedException e) 
            {  
                e.printStackTrace();  
            }  
            String now = new SimpleDateFormat("yyyyMMddHHmm").format(new Date());    
            if (!now.equals(time)){  
                lock.writeLock().lock();  
                time = now;  
                value.set(getInitial());  
                lock.writeLock().unlock();  
            }  
        }  
	}

	@Override
	public String next() 
	{
		lock.readLock().lock();
		
		int index = value.getAndIncrement();
		
		if(index==999999999)
		{
			value.set(0);
		}
		
		String num = String.valueOf(index);
		
		time = String.valueOf(System.currentTimeMillis());
		
		StringBuilder number = new StringBuilder();
		
		int maxLength = 9;
		
		if(num.length()<maxLength)
		{
			for(int i=0;i<(maxLength-num.length());i++)
			{
				number.append("0");
			}
		}
		number.append(num);
		
        StringBuffer sb = new StringBuffer(getPrefix()).append(getSplitString()).append(time).append(getSplitString()).append(number.toString());  
        
        lock.readLock().unlock();  
        
        return sb.toString(); 
	}
}

每個dao大體情況:

@Repository("XXXDao")
public class XXXDaoHibernate extends GenericDaoHibernate<XXX(這個是實體), String> implements
XXXDao {
        //這裡有需要就重寫next(),沒需要直接在service層用XXXDao.next()呼叫拿到主鍵

}