在项目中经常会遇到动态创建表的场景,例如,统计用户日活,每天活跃的用户数据需要放入单独的表中(eg: tb_user_active_20200327,tb_user_active_20200328)。这些和日期相关的表需要我们定时去创建,一般会通过定时任务来实现。具体参考以下示例:
- 表结构
create table tb_user_active(
id int(11) primary key auto_increment comment 'id',
user_id int(11) comment '用户ID',
active_time datetime comment '活跃时间'
)
- UserActiveService
import com.test.mybatis.mapper.UserActiveMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
/**
*/
@Service
public class UserActiveService {
/**
* 日活表前缀
*/
public static final String USER_ACTIVE_TABLE_PREFIX = "tb_user_active_";
@Autowired(required = false)
UserActiveMapper userActiveMapper;
/**
* 定时器(每天凌晨1点执行一次)
*/
@Scheduled(cron = "0 0 1 * * ?")
public void createTableJob() {
// 每次创建多张表(如果一次创建一张表,可能会有问题,比如由于未知原因,导致定时任务未执行,或者执行出错,此时表会创建失败)
int num = 3;
for(int i=1; i<=num; i++) {
Calendar c = Calendar.getInstance();
c.add(Calendar.DAY_OF_MONTH, i);
createTable(c.getTime());
}
}
/**
* 获取表名
* @param date
* @return
*/
public String getTableName(Date date) {
return USER_ACTIVE_TABLE_PREFIX + new SimpleDateFormat("yyyyMMdd").format(date);
}
/**
* 创建表
* @param date
*/
public void createTable(Date date) {
String sql = "create table if not exists " + getTableName(date) + "(
" +
" id int(11) primary key auto_increment comment 'id',
" +
" user_id int(11) comment '用户ID',
" +
" active_time datetime comment '活跃时间'
" +
")";
userActiveMapper.createTable(sql);
}
}
- UserMapper
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
import org.springframework.stereotype.Repository;
/**
*/
@Repository
public interface UserActiveMapper {
/**
* 建表
* @param createTabelSql
*/
@Update("${createTabelSql}")
void createTable(@Param("createTabelSql")String createTabelSql);
}
以上是自动建表的主要代码,如需源码,请点击获取 auto-create-table
注意:如果出现java.lang.IllegalAccessError: org.apache.commons.dbcp.DelegatingPreparedStatement.isClosed()Z 错误,可能是dbcp和mybatis版本不兼容导致,具体版本请参考pom.xml