刚完成的项目需求:一个全省范围内的项目,所有市访问同一个网站,所有市对自身的数据有管理权限;在这些数据中,一公告这么一个实体,所有管理员均可向这张表中写入数据,每个月的数据都会超过万条。为避免公告表变成巨无霸,现将公告表按区域、公告类型分表。
主要代码就一个类:
/**
*
*/
package com.hbcgs.notice.interceptor;
import org.hibernate.EmptyInterceptor;
/**
* @author Geloin
*
*/
@SuppressWarnings("serial")
public class NoticeInfoInterceptor extends EmptyInterceptor {
private String targetTableName;// 目标母表名
private String tempTableName;// 操作子表名
public NoticeInfoInterceptor() {
}// 为其在spring好好利用 我们生成公用无参构造方法
@Override
public java.lang.String onPrepareStatement(java.lang.String sql) {
sql = sql.replaceAll(targetTableName, tempTableName);
return sql;
}
public String getTargetTableName() {
return targetTableName;
}
public void setTargetTableName(String targetTableName) {
this.targetTableName = targetTableName;
}
public String getTempTableName() {
return tempTableName;
}
public void setTempTableName(String tempTableName) {
this.tempTableName = tempTableName;
}
}
在控制分表时,在管理数据层,假设是Dao层,进行以下处理:
/**
* 保存公告信息,分表保存
*
* @param info
*/
public void save(NoticeInfo info) {
SessionFactory sf = super.getHibernateTemplate().getSessionFactory();
NoticeInfoInterceptor interceptor = new NoticeInfoInterceptor();
// 要拦截的目标表名
interceptor.setTargetTableName("noticeinfo");
String realTableName = "NOTICEINFO_" + info.getArea().getAreaId() + "_"
+ info.getType();
// 要替换的子表名
interceptor.setTempTableName(realTableName);
try {
if (!existsTableNames.contains(realTableName)) {
checkTable(sf.openSession(), realTableName);
existsTableNames.add(realTableName);
}
} catch (Exception e) {
e.printStackTrace();
}
Session session = sf.openSession(interceptor);
try {
// 获取事务
Transaction tx = session.beginTransaction();
// 开启事务
tx.begin();
// 保存和更新
session.saveOrUpdate(info);
// 提交
tx.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
session.close();
}
}
Dao层继承了org.springframework.orm.hibernate3.support.HibernateDaoSupport类,checkTable方法主要是为了检查表是否存在,不存在时需要建表:
/**
* 检查表是否存在,不存在时创建
*
* @param session
* @param tableName
* @throws Exception
*/
private void checkTable(Session session, String tableName) throws Exception {
try {
// 测试查询
String testSql = "select * from " + tableName;
Query query = session.createSQLQuery(testSql);
query.setFirstResult(0);
query.setMaxResults(1);
query.uniqueResult();
} catch (HibernateException e) {
// Connection conn = session.connection();
// Statement stmt = conn.createStatement();
StringBuilder builder = new StringBuilder();
builder.append("create table ");
builder.append(tableName);
builder.append("(");
builder.append("ID NUMBER(10) not null,");
builder.append("STR1 VARCHAR2(255),");
builder.append("STR2 VARCHAR2(255),");
builder.append("STR3 VARCHAR2(255),");
builder.append("STR4 VARCHAR2(255),");
builder.append("STR5 VARCHAR2(255),");
builder.append("STR6 VARCHAR2(255),");
builder.append("STR7 VARCHAR2(255),");
builder.append("STR8 VARCHAR2(255),");
builder.append("STR9 VARCHAR2(255),");
builder.append("STR10 VARCHAR2(255),");
builder.append("PYEAR NUMBER(10),");
builder.append("PMONTH NUMBER(10),");
builder.append("TYPE NUMBER(10),");
builder.append("AREA_ID NUMBER(10)");
builder.append(")");
Query query = session.createSQLQuery(builder.toString());
query.executeUpdate();
} finally {
session.flush();
session.close();
}
}
实现方法显然比较粗糙,不过暂时够解决问题,Mark一下。