前言
mybatis 和 hibernate 是最受欢迎的orm框架之二, 但是我一直觉得hibernate这个框架对于我来说还是太重了, 而且稍有不注意性能上就会损失巨大, 所以mybatis成为了我的首选。
但是hibernate有一个功能我非常喜欢, 就是可以根据实体类自动建表, 那我就想mybatis可不可以也做到这一点呢? 那么就让我来介绍一下ACTable这个开源工具, 他可以让mybatis实现自动建表的功能, 具体的使用方法大家可以通过上面的链接查看, 这篇博客主要是来记录一下这个工具的实现思路。
实现思路
注解层
这个工具有三个注解, 分别是 Column
, LengthCount
和 Table
- Column 是注解到字段上的, 用来指定字段的名字, 类型, 长度等
- LengthCount 是用来标记数据库类型的长度
- Table 用来指定表名
入口
在manager.handler.StartUpHandler
中定义了入口方法 startHandler()
, 该方法使用了@PostConstruct
注解, 该注解是Spring的注解, 使用了该注解的方法会在依赖注入(@Autowired
)之后自动执行。
1 2 3 4 5 6 7 8 9 10 11 12 13
| public void startHandler() {
if (MYSQL.equals(databaseType)) { log.info("databaseType=mysql,开始执行mysql的处理方法"); sysMysqlCreateTableManager.createMysqlTable(); }else{ log.info("没有找到符合条件的处理方法!"); } }
|
可以看到该方法调用了SysMysqlCreateTableManager
这个类的createMysqlTable()
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| public void createMysqlTable() {
if ("none".equals(tableAuto)) { log.info("配置mybatis.table.auto=none,不需要做任何事情"); return; }
Map<String, Object> mySqlTypeAndLengthMap = mySqlTypeAndLengthMap();
Set<Class<?>> classes = ClassTools.getClasses(pack);
Map<String, List<Object>> newTableMap = new HashMap<String, List<Object>>();
Map<String, List<Object>> modifyTableMap = new HashMap<String, List<Object>>();
Map<String, List<Object>> addTableMap = new HashMap<String, List<Object>>();
Map<String, List<Object>> removeTableMap = new HashMap<String, List<Object>>();
Map<String, List<Object>> dropKeyTableMap = new HashMap<String, List<Object>>();
Map<String, List<Object>> dropUniqueTableMap = new HashMap<String, List<Object>>();
allTableMapConstruct(mySqlTypeAndLengthMap, classes, newTableMap, modifyTableMap, addTableMap, removeTableMap, dropKeyTableMap, dropUniqueTableMap);
createOrModifyTableConstruct(newTableMap, modifyTableMap, addTableMap, removeTableMap, dropKeyTableMap, dropUniqueTableMap); }
|
嗯, 注释写的已经非常清楚了, 首先检测用户配置的状态是什么, 然后构建操作表的sql, 最后进行实际操作。
值得注意的是, 这里有一个操作可以根据用户配置的包名来获取到所有实体类的Class, 这篇博文对这里进行了分析。
构建出全部表的增删改的map
看完了大体的思路, 接下来就来看看是怎么具体实现的。
首先来看看他是怎么构建出全部表的增删改的map的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
|
private void allTableMapConstruct(Map<String, Object> mySqlTypeAndLengthMap, Set<Class<?>> classes, Map<String, List<Object>> newTableMap, Map<String, List<Object>> modifyTableMap, Map<String, List<Object>> addTableMap, Map<String, List<Object>> removeTableMap, Map<String, List<Object>> dropKeyTableMap, Map<String, List<Object>> dropUniqueTableMap) { for (Class<?> clas : classes) {
Table table = clas.getAnnotation(Table.class); if (null == table) { continue; }
List<Object> newFieldList = new ArrayList<Object>(); List<Object> removeFieldList = new ArrayList<Object>(); List<Object> addFieldList = new ArrayList<Object>(); List<Object> modifyFieldList = new ArrayList<Object>(); List<Object> dropKeyFieldList = new ArrayList<Object>(); List<Object> dropUniqueFieldList = new ArrayList<Object>();
tableFieldsConstruct(mySqlTypeAndLengthMap, clas, newFieldList);
if ("create".equals(tableAuto)) { createMysqlTablesMapper.dorpTableByName(table.name()); }
int exist = createMysqlTablesMapper.findTableCountByTableName(table.name());
if (exist == 0) { newTableMap.put(table.name(), newFieldList); } else { List<SysMysqlColumns> tableColumnList = createMysqlTablesMapper .findTableEnsembleByTableName(table.name());
List<String> columnNames = ClassTools.getPropertyValueList(tableColumnList, SysMysqlColumns.COLUMN_NAME_KEY);
buildAddAndRemoveAndModifyFields(mySqlTypeAndLengthMap, modifyTableMap, addTableMap, removeTableMap, dropKeyTableMap, dropUniqueTableMap, table, newFieldList, removeFieldList, addFieldList, modifyFieldList, dropKeyFieldList, dropUniqueFieldList, tableColumnList, columnNames);
} } }
|
首先遍历实体类class集合, 检测是否声明了@Table
注解, 这里利用了反射机制, 使用了Class类的getAnnotation(Class<?>)
方法, 检测该类是否声明了参数中传入的注解。
接着声明了一些集合, 分别用来存储新增表的字段, 删除的字段, 修改的字段, 新增的字段, 删除主键的字段以及删除唯一约束的字段。
然后将所有的实体类的字段获取到, 这篇博文对这里进行了分析。
接着如果用户声明的策略是create, 则删除所有的表重新创建。
接着判断表是否存在, 当表不存在时, 直接使用所有的字段和表名初始化集合。当表已经存在时, 将已经存在的表的结构和实体类中声明的表的结构进行对比, 将所有需要修改的字段初始化到集合中。