sqlaction 自动生成 JDBC 代码的数据库持久层工具开源项目

我要开发同款
匿名用户2019年04月18日
41阅读
开发技术Java
所属分类程序开发、代码生成工具
授权协议Apache

作品详情

sqlaction-自动生成JDBC代码的数据库持久层工具1.概述

厌烦了MyBatis和JPA(Hibernate)的冗余配置和繁琐使用,以及XML拷来拷去,写那么多Mapper要是直接用JDBC早就写完了,如果使用一个框架/工具比不使用而带来更多的心智负担,那还不如不用。其实,直接使用JDBC还是蛮干净和高性能的,只要解决其三个痛点:

手工编写数据库表实体类。手工编写大量setString和getString代码,尤其还要人工保证字段序号递增。因为直接写SQL,涉及不同DBMS的SQL方言时,移植性不好,比如分页查询。

能否造一个更好的轮子?

于是,我花了十多个晚上,结合之前在C技术栈中的设计和经验,结合JAVA特点,写了sqlaction。

sqlaction是自动生成JDBC代码的数据库持久层工具,它为应用提供了类似MyBatis和Hibernate操作数据库能力,但更轻量级和几乎消除了所有的手工冗余编码,提高开发效率,也易于与其它框架搭配使用。sqlaction读取数据库中的表结构元信息和少量配置文件信息(SQL),自动生成数据库表实体类,自动生成基于JDBC的SQL动作方法代码,自动生成拦截器框架等代码,应用调用其自动生成的代码就能极其快捷的操作数据库,同时还拥有JDBC的高性能,更重要的是开发者能直接看到底层操作代码,增加自主可控,没有低效的反射,没有复杂的热修改字节码,没有庞大笨重的隐藏核心。

2.一个DEMO

放一个DEMO感受一下:

2.1.建表DDL

ddl.sql

CREATETABLE`sqlaction_demo`(`id`int(11)NOTNULLAUTO_INCREMENTCOMMENT'编号',`name`varchar(32)COLLATEutf8mb4_binNOTNULLCOMMENT'名字',`address`varchar(128)COLLATEutf8mb4_binDEFAULTNULLCOMMENT'地址',PRIMARYKEY(`id`),KEY`sqlaction_demo`(`name`))ENGINE=InnoDBAUTO_INCREMENT=6DEFAULTCHARSET=utf8mb4COLLATE=utf8mb4_bin2.2.新建JAVA项目

只依赖数据库连接库和作者另一个JSON解析器okjson,引入mysql-connector-java-X.Y.Z.jar、okjson-0.0.9.0.jar。

建立包目录,在包目录或上级某一级目录中创建数据库连接配置文件dbserver.conf.json,工具会从执行目录开始往上查找,只要某一级目录中存在这个配置文件即可。

{"driver":"com.mysql.jdbc.Driver","url":"jdbc:mysql://127.0.0.1:3306/calvindb?serverTimezone=GMT","user":"calvin","pwd":"calvin"}

在包目录或上级某一级目录中创建SQL动作配置文件sqlaction.conf.json,工具会从执行目录开始往上查找,只要某一级目录中存在这个配置文件即可。

{"database":"calvindb","tables":[{"table":"sqlaction_demo","sqlactions":["SELECT*FROMsqlaction_demo","SELECT*FROMsqlaction_demoWHEREname=?","INSERTINTOsqlaction_demo","UPDATEsqlaction_demoSETaddress=?WHEREname=?@@METHOD(updateAddressByName)","DELETEFROMsqlaction_demoWHEREname=?"]}],"javaPackage":"xyz.calvinwilliams.sqlaction.demo"}2.3.在包目录中执行sqlaction工具

我把执行命令行包成批处理文件后执行,欢迎懂Eclipse插件开发的同学帮我写个插件:)

pp.bat

java-Dfile.encoding=UTF-8-classpath"D:\Work\mysql-connector-java-8.0.15\mysql-connector-java-8.0.15.jar;%USERPROFILE%\.m2\repository\xyz\calvinwilliams\okjson\0.0.9.0\okjson-0.0.9.0.jar;%USERPROFILE%\.m2\repository\xyz\calvinwilliams\sqlaction\0.2.1.0\sqlaction-0.2.1.0.jar"xyz.calvinwilliams.sqlaction.SqlActionGencodepause

注意:使用Maven管理的项目,在添加sqlaction依赖声明后,maven会自动下载sqlaction以及其依赖okjson的jar到C:\User\用户名\.m2\repository\xyz\calvinwilliams\下。sqlaction依赖声明见最后面“关于本项目”章节。

执行pp.bat,工具sqlaction会从执行目录开始往上查找读入dbserver.conf.json和sqlaction.conf.json并自动生成所有代码。

/////////////////////////////////////////////////////////////////////////////////sqlactionv0.0.8.0///Copyrightbycalvin<calvinwilliams@163.com,calvinwilliams@gmail.com>//////////////////////////////////////////////////////////////////////////////---dbserverConf---dbms[mysql]driver[com.mysql.jdbc.Driver]url[jdbc:mysql://127.0.0.1:3306/calvindb?serverTimezone=GMT]user[calvin]pwd[calvin]---sqlactionConf---database[calvindb]table[sqlaction_demo]sqlaction[SELECT*FROMsqlaction_demo]sqlaction[SELECT*FROMsqlaction_demoWHEREname=?]sqlaction[INSERTINTOsqlaction_demo]sqlaction[UPDATEsqlaction_demoSETaddress=?WHEREname=?@@METHOD(updateAddressByName)]sqlaction[DELETEFROMsqlaction_demoWHEREname=?]SqlActionTable.getTableInDatabase[sqlaction_demo]............***NOTICE:WriteSqlactionDemoSAO.javacompleted!!!

如果没有出现***ERROR:...说明工具执行成功,在执行所在目录中自动生成了一个JAVA源代码文件

SqlactionDemoSAO.java

//Thisfilegeneratedbysqlactionv0.2.1.0packagexyz.calvinwilliams.sqlaction.demo;importjava.math.*;importjava.util.*;importjava.sql.Time;importjava.sql.Timestamp;importjava.sql.Connection;importjava.sql.Statement;importjava.sql.PreparedStatement;importjava.sql.ResultSet;publicclassSqlactionDemoSAO{intid;//编号Stringname;//名字Stringaddress;//地址int_count_;//definingfor'SELECTCOUNT(*)'//SELECT*FROMsqlaction_demopublicstaticintSELECT_ALL_FROM_sqlaction_demo(Connectionconn,List<SqlactionDemoSAO>sqlactionDemoListForSelectOutput)throwsException{Statementstmt=conn.createStatement();ResultSetrs=stmt.executeQuery("SELECT*FROMsqlaction_demo");while(rs.next()){SqlactionDemoSAOsqlactionDemo=newSqlactionDemoSAO();sqlactionDemo.id=rs.getInt(1);sqlactionDemo.name=rs.getString(2);sqlactionDemo.address=rs.getString(3);sqlactionDemoListForSelectOutput.add(sqlactionDemo);}returnsqlactionDemoListForSelectOutput.size();}//SELECT*FROMsqlaction_demoWHEREname=?publicstaticintSELECT_ALL_FROM_sqlaction_demo_WHERE_name_E_(Connectionconn,List<SqlactionDemoSAO>sqlactionDemoListForSelectOutput,String_1_name)throwsException{PreparedStatementprestmt=conn.prepareStatement("SELECT*FROMsqlaction_demoWHEREname=?");prestmt.setString(1,_1_name);ResultSetrs=prestmt.executeQuery();while(rs.next()){SqlactionDemoSAOsqlactionDemo=newSqlactionDemoSAO();sqlactionDemo.id=rs.getInt(1);sqlactionDemo.name=rs.getString(2);sqlactionDemo.address=rs.getString(3);sqlactionDemoListForSelectOutput.add(sqlactionDemo);}returnsqlactionDemoListForSelectOutput.size();}//INSERTINTOsqlaction_demo(name,address)VALUES(?,?)publicstaticintINSERT_INTO_sqlaction_demo(Connectionconn,SqlactionDemoSAOsqlactionDemo)throwsException{PreparedStatementprestmt=conn.prepareStatement("INSERTINTOsqlaction_demo(name,address)VALUES(?,?)");prestmt.setString(1,sqlactionDemo.name);prestmt.setString(2,sqlactionDemo.address);returnprestmt.executeUpdate();}//UPDATEsqlaction_demoSETaddress=?WHEREname=?publicstaticintupdateAddressByName(Connectionconn,String_1_address_ForSetInput,String_1_name_ForWhereInput)throwsException{PreparedStatementprestmt=conn.prepareStatement("UPDATEsqlaction_demoSETaddress=?WHEREname=?");prestmt.setString(1,_1_address_ForSetInput);prestmt.setString(2,_1_name_ForWhereInput);returnprestmt.executeUpdate();}//DELETEFROMsqlaction_demoWHEREname=?publicstaticintDELETE_FROM_sqlaction_demo_WHERE_name_E_(Connectionconn,String_1_name)throwsException{PreparedStatementprestmt=conn.prepareStatement("DELETEFROMsqlaction_demoWHEREname=?");prestmt.setString(1,_1_name);returnprestmt.executeUpdate();}}

SqlactionDemoSAU.java

//Thisfilegeneratedbysqlactionv0.2.1.0packagexyz.calvinwilliams.sqlaction;importjava.math.*;importjava.util.*;importjava.sql.Time;importjava.sql.Timestamp;importjava.sql.Connection;importjava.sql.Statement;importjava.sql.PreparedStatement;importjava.sql.ResultSet;publicclassSqlactionDemoSAU{}

工具sqlaction内部处理流程如下:

首先查找执行目录中的数据库连接配置文件dbserver.conf.json,如果没有找到就迭代往上级目录继续找,从该配置文件中获得数据库连接配置信息。然后以相同的查找逻辑读取sqlaction.conf.json获得数据库名、表列表、以及每张表需要执行的SQL语句列表等信息。配置文件往上查找机制是为了灵活适应不同规模项目目录的规划。连接数据库,读取表结构元信息,每张表对应自动生成数据库表实体类和SQL动作方法JAVA源代码文件XxxSao.java和用户自定义代码文件XxxSau.java,,sqlaction配置文件中的每一条SQL自动解析生成基于JDBC的JAVA方法,从此再也不用手工写JDBC代码了!2.4.到目前为止,一行JAVA代码都没写,现在开始写应用代码

Demo.java

packagexyz.calvinwilliams.sqlaction.demo;importjava.sql.Connection;importjava.sql.DriverManager;importjava.sql.SQLException;importjava.util.LinkedList;importjava.util.List;publicclassDemo{publicstaticvoidmain(String[]args){Connectionconn=null;List<SqlactionDemoSAO>sqlactionDemoList=null;SqlactionDemoSAOsqlactionDemo=null;SqlactionDemoSAOsqlactionDemoForSetInput=null;SqlactionDemoSAOsqlactionDemoForWhereInput=null;intnret=0;//Connecttodatabasetry{Class.forName("com.mysql.jdbc.Driver");conn=DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/calvindb?serverTimezone=GMT","calvin","calvin");}catch(ClassNotFoundExceptione1){e1.printStackTrace();}catch(SQLExceptione){e.printStackTrace();}try{conn.setAutoCommit(false);//Deleterecordswithnamenret=SqlactionDemoSAO.DELETE_FROM_sqlaction_demo_WHERE_name_E_(conn,"Calvin");if(nret<0){System.out.println("SqlactionDemoSAO.DELETE_FROM_sqlaction_demo_WHERE_name_E_failed["+nret+"]");conn.rollback();return;}else{System.out.println("SqlactionDemoSAO.DELETE_FROM_sqlaction_demo_WHERE_name_E_ok,rows["+nret+"]effected");}//InsertrecordsqlactionDemo=newSqlactionDemoSAO();sqlactionDemo.name="Calvin";sqlactionDemo.address="Myaddress";nret=SqlactionDemoSAO.INSERT_INTO_sqlaction_demo(conn,sqlactionDemo);if(nret<0){System.out.println("SqlactionDemoSAO.INSERT_INTO_sqlaction_demofailed["+nret+"]");conn.rollback();return;}else{System.out.println("SqlactionDemoSAO.INSERT_INTO_sqlaction_demook");}//Updaterecordwithnamenret=SqlactionDemoSAO.updateAddressByName(conn,"Myaddress2","Calvin");if(nret<0){System.out.println("SqlactionDemoSAO.updateAddressByNamefailed["+nret+"]");conn.rollback();return;}else{System.out.println("SqlactionDemoSAO.updateAddressByNameok,rows["+nret+"]effected");}//QueryrecordssqlactionDemoList=newLinkedList<SqlactionDemoSAO>();nret=SqlactionDemoSAO.SELECT_ALL_FROM_sqlaction_demo(conn,sqlactionDemoList);if(nret<0){System.out.println("SqlactionDemoSAO.SELECT_ALL_FROM_sqlaction_demofailed["+nret+"]");conn.rollback();return;}else{System.out.println("SqlactionDemoSAO.SELECT_ALL_FROM_sqlaction_demook");for(SqlactionDemoSAOr:sqlactionDemoList){System.out.println("id["+r.id+"]name["+r.name+"]address["+r.address+"]");}}conn.commit();}catch(Exceptione){try{conn.rollback();}catch(Exceptione2){return;}}return;}}2.5.执行SqlactionDemoSAO.DELETE_FROM_sqlaction_demo_WHERE_name_E_ok,rows[1]effectedSqlactionDemoSAO.INSERT_INTO_sqlaction_demookSqlactionDemoSAO.UPDATE_sqlaction_demo_SET_address_E_WHERE_name_E_ok,rows[1]effectedSqlactionDemoSAO.SELECT_ALL_FROM_sqlaction_demookid[15]name[Calvin]address[Myaddress2]

总结:

对表的增删改查只需调用前面自动生成的数据库表实体类中的方法即可,而且底层执行代码可随时查看,没有什么秘密,没有什么高深的技术。

工具sqlaction只在开发阶段使用,与运行阶段无关,说到底只是在应用与JDBC之间自动生成了薄薄的一层代码而已,把大量手工冗余代码都自动生成了,让开发者节省大量时间而去关注业务,减少大量机械操作减轻心智负担,提高生产力,早点做完工作回家抱女盆友/老婆:)

6.关于本项目

欢迎使用sqlaction,如果你在使用中碰到了问题请告诉我,谢谢^_^

源码托管地址: Gitee、github

ApacheMaven

<dependency><groupId>xyz.calvinwilliams</groupId><artifactId>sqlaction</artifactId><version>0.2.1.0</version></dependency>

GradleKotlinDSL

compile("xyz.calvinwilliams:sqlaction:0.2.1.0")7.关于作者

厉华,右手C,左手JAVA,写过小到性能卓越方便快捷的日志库、HTTP解析器、日志采集器等,大到交易平台/中间件等,分布式系统实践者,容器技术专研者,目前在某城商行负责基础架构。

通过邮箱联系我: 网易、Gmail

声明:本文仅代表作者观点,不代表本站立场。如果侵犯到您的合法权益,请联系我们删除侵权资源!如果遇到资源链接失效,请您通过评论或工单的方式通知管理员。未经允许,不得转载,本站所有资源文章禁止商业使用运营!
下载安装【程序员客栈】APP
实时对接需求、及时收发消息、丰富的开放项目需求、随时随地查看项目状态

评论