搭建java代码框架
引入辅助类和基类
PKgen为 PK 生成器
package net.sw.util;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
*
* 用来生成唯一的PK
* 该 PK 生成器生成 19 位的唯一 long 值,精确到万分之一秒,
* 最后一位为尾数,用来在集群环境下保证PK的唯一性。
*
* 该PK生成虽然依赖于时间,但是在运行过程中改变时间不会影响PK,
* 但是如果将系统时间后调,然后重新启动,有可能造成PK重复。
*
* 该 PK 生成器不依赖于数据库,相比依赖数据表的PK生成器,速度快,而且值可读
*
* @author <a href="mailto:yang_y@sysnet.com.cn">Young Yang</a>
*/
public class PKgen {
/**
* PK生成锁,用来限定同一时刻只有一个线程进入PK生成计算
*/
private final Lock LOCK = new ReentrantLock();
/**
* 初始化时的毫秒数,因为该时间会随系统时间的改变而改变,
* 所以计算方法为该时间加上通过 nanoTime 计算出来的时间差
*/
private final static Long startMilli = System.currentTimeMillis();
/**
* 初始化时的纳秒数,用来计量时间差,nanoTime不会随着系统时间的修改而改变
*/
private final static long startNano = System.nanoTime();
/**
* 记录上一次生成 的 PK,如果新生成的PK和上次相等,则需要再次生成
*/
private volatile long lastPK = -1;
//private final static SimpleDateFormat dateFormat = new SimpleDateFormat(
// "yyyyMMddHHmmssSSS");
private final static SimpleDateFormat dateFormat = new SimpleDateFormat(
"yyMMddHHmmssSSS");
/**
* 返回的long PK的尾数,尾数可以用来在集群环境中判断该PK由哪一个节点产生
* 尾数通过配置设定
*/
private int suffix = 0;
private static final Map<Integer, PKgen> instanceMap = new HashMap<Integer, PKgen>();
// 必须提供正确的参数,以保证 suffix 在机群环境的唯一性
private PKgen(int suffix) {
this.suffix = suffix;
}
public synchronized static PKgen getInstance() {
return getInstance(0);
}
/**
* 单机环境下,应该保证用相同的 suffix
* 在集群环境中,不同的机器必须提供不同的 suffix 来保证生成的ID的唯一性
* @param suffix
* 唯一标识好
*/
public synchronized static PKgen getInstance(int suffix) {
PKgen pkgen;
if (!instanceMap.containsKey(suffix)) {
pkgen = new PKgen(suffix);
instanceMap.put(suffix, pkgen);
}
else {
pkgen = instanceMap.get(suffix);
}
return pkgen;
}
/**
* 返回下一个 long 型 PK, format: 2006111423361344491 <br>
* yyyyMMddHHmmssSSS + Macro Seconds + suffix
* @return long PK
*/
public long nextPK() {
LOCK.lock();
try {
long newPK;
do {
long pastNano = System.nanoTime() - startNano; // 纳秒时间差
long milliTime = pastNano / 1000000; // 取得毫秒差
long macroTime = (pastNano / 100000) % 10; // 取得微秒第一位,
// 计算出来的long PK,精度到万分之一秒(百微妙),加上尾数,一共19位,这是 Long.MAX_VALUE的最大位数了
newPK = Long.parseLong(dateFormat.format(new Date(startMilli
+ milliTime))
+ macroTime + suffix);
}
while (lastPK == newPK); // 如果生成的相同,则再次计算
lastPK = newPK; // 设置 lastPK
return newPK;
}
finally {
LOCK.unlock();
}
}
public static void main(String[] args) throws Exception {
PKgen pkg = PKgen.getInstance(0);
int i = 0;
long now = System.currentTimeMillis();
while (i++ < 10) {
System.out.println(pkg.nextPK());
}
System.out.println("Time: " + (System.currentTimeMillis() - now));
}
}
如注释所述该 PK 生成器生成 19 位的long值,java中的Long在Flex中将转换为Number。Flex的Nubmer类型能精确处理的数据只有17位,所以注意43到46行,我在此处做了一点改动屏蔽了年的前两位,这样生成的 PK 实际上位17位。
BaseDomain
package net.sw.base.domain;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
/**
* 领域对象基类
*
* @author vyyv
*
*/
@SuppressWarnings("serial")
@MappedSuperclass
public abstract class BaseDomain implements java.io.Serializable {
public BaseDomain() {
// 对象有可能是在客户端由flex生成,不会执行这个构造方法,所以不能在此处添加ID
// this.id = PKgen.getInstance(0).nextPK();
this.id=new Long(0);
}
/**
* 领域对象编码
*/
@Id
@Column
Long id;
/**
* 领域对象名称
*/
@Column
String name;
/**
* 领域对象描述
*/
@Column
String description;
/**
* 领域对象创建时间
*/
@Column
Date createtime;
(setter getter 略)
........... ............
}
GenericDao
package net.sw.base.dao;
import java.io.Serializable;
import java.util.List;
/**
*
* @author vyyv
* @param <T>
* a type variable
* @param <PK>
* the primary key for that type
*/
public interface GenericDao<T, PK extends Serializable> {
/**
* 获取所有对象实例
* @return 由所有对象实例组成的List
*/
List<T> getAll();
/**
* 获取一个对象实例
* 如果不存在抛出ObjectRetrievalFailureException
* @param id 对象ID
* @return 一个对象实例
* @see org.springframework.orm.ObjectRetrievalFailureException
*/
T get(PK id);
/**
* 判断对象实例是否存在
*@param id 对象ID
* @return - 存在返回true,不存在返回false
*/
boolean exists(PK id);
/**
* 保存对象实例 - 新建或更新
* @param object 需要保存的对象
* @return 保存之后的对象(保存的动作可能会修改对象,例如:ID,createtime)
*/
T save(T object);
/**
* 删除对象实例
* @param id
*/
void remove(PK id);
}
GenericManager
package net.sw.base.service;
import java.io.Serializable;
import java.util.List;
/**
*
* @author vyyv</a>
* @param <T>
* a type variable
* @param <PK>
* the primary key for that type
*/
public interface GenericManager<T, PK extends Serializable> {
/**
* 获取所有对象实例
* @return 由所有对象实例组成的List
*/
List<T> getAll();
/**
* 根据ID获取一个对象实例
* @param id 对象ID
* @return 一个对象实例
*/
T get(PK id);
/**
* 判断对象实例是否存在
*@param id 对象ID
* @return - 存在返回true,不存在返回false
*/
boolean exists(PK id);
/**
* 保存对象实例 - 新建或更新
* @param object 需要保存的对象
* @return 保存之后的对象(保存的动作可能会修改对象,例如:ID,createtime)
*/
T save(T object);
/**
* 删除对象实例
* @param id
*/
void remove(PK id);
}