InnoDB:有事务、支持行锁,适用于并发处理的业务。针对单个操作,因为有事务(即使查询也是自动提交一个事务),相对开销大,但支持并发处理不同行数据,所以吞吐量大。
MyISAM:无事务,表锁,适合少量并发操作。针对单个操作,因为无事务,表锁时间开销小,读取速度快。但崩溃不可恢复,所以一般用于不重要的,或只供查询的业务使用。
对于集群分布式服务来说,需要保证某个服务的表的唯一id,假设不再使用mysql的自增id。有很多方式,这里举例一个。为了避免频繁读取可用id,集群中每个服务器每次取一定量的可用的id范围,不够了再取。
方案:主库建新表存储唯一id的信息,目前值、每次取得值范围。
service:
@Service
public class AutoNumberImplService implements AutoNumberService {
private ConcurrentHashMap<String, AutoNumberItem> type2AutoNumberMap = new ConcurrentHashMap<String, AutoNumberItem>();
@Resource
private AutoNumberDao dao;
@Override
public int getNextNumber(AutoNumberType type) {
return getNextNumber(type, false);
}
public int getNextNumber(AutoNumberType type, boolean needFromDB) {
AutoNumberItem item = type2AutoNumberMap.get(type.name);
if (needFromDB || item == null) {
AutoNumberItem newStep = getNewStep(type);
type2AutoNumberMap.putIfAbsent(type.name, newStep);
item = newStep;
}
int next = item.getNext();
int maxNumber = item.getMax();
if (next > maxNumber) {
return getNextNumber(type, true);
}
return next;
}
@Transactional
private AutoNumberItem getNewStep(AutoNumberType type) {
AutoNumberItem item = dao.select(type.name);
item = new AutoNumberItem(item.getStart(), item.getStep());//事务里查询出来的结果适用空构造函数,所以对象的其他值为默认值
Map<String, Object> params = new HashMap<String, Object>();
params.put("name", type.name);
params.put("inc", item.getStep());
dao.update(params);
return item;
}
}
model:
public class AutoNumberItem {
private int start;
private int step;
private int max;
private int now;
public AutoNumberItem() {
}
//奇葩的是,mybites查询出来适用默认构造函数
public AutoNumberItem(int start, int step) {
this.start = start;
this.step = step;
this.max = this.start + this.step;
this.now = start;
}
public synchronized int getNext() {
now += 1;
return now;
}
public int getMax() {
return this.max;
}
public int getStart() {
return start;
}
public int getStep() {
return step;
}
}
配置文件:
<mapper namespace="com.liu.dao.AutoNumberDao"> <resultMap type="com.liu.model.AutoNumberItem" id="itemMap"> <result column="Start" property="start" /> <result column="Step" property="step" /> </resultMap> <!-- mybsits_config中配置的alias类别名,也可直接配置resultType为类路劲 --> <select id="select" parameterType="String" resultMap="itemMap"> <![CDATA[ select Start,Step from autonumber where name=#{name} FOR UPDATE ]]> </select> <insert id="insert" parameterType="com.liu.model.AutoNumberItem" flushCache="true"> insert into autonumber (Name, Start, Step) values (#{name,jdbcType=VARCHAR}, #{start,jdbcType=INTEGER}, #{step,jdbcType=INTEGER}) </insert> <update id="update"> update autonumber <trim prefix="set" suffixOverrides=","> <if test="inc!=null">start=start+#{inc,jdbcType=INTEGER},</if> </trim> where Name=#{name,jdbcType=VARCHAR} </update> </mapper>