LikeSql——让你更优雅地写SQL
?
LikeSql是什么
LikeSql是我写一个开源的小框架(http://code.google.com/p/likesql/),目标是提供一个更优雅地处理SQL的一个方案,希望能够替代PreparedStatement和直接拼接SQL。虽然现在还有没有正式的release版本,我还在为此努力。
?
设计宗旨:
专注于优雅地编写SQL和易读性保持细小和灵活?
一些代码示例:
?
public void testAtStyleExpression(){LikeSql sql=DML.select("id,name") .from("user") .where(AtExp.at("(name =@name or id=@id) and gender=@gender") .set("id", 1) .set("name", "John") .set("gender", "M"));String eSql="SELECT id,name FROM user WHERE (name ='John' or id=1) and gender='M'";String eTpl="SELECT id,name FROM user WHERE (name =? or id=?) and gender=?";assertEquals(eSql,sql.toString());assertEquals(eTpl,sql.toTemplate());}public void testInExpression(){LikeSql sSql=DML.select("id,name") .from("user") .where(QuestExp.qt("id in (?)").set(1,ArrayExp.array(new int[]{1,3,6})));String eSql="SELECT id,name FROM user WHERE id in (1,3,6)";String eTpl="SELECT id,name FROM user WHERE id in (?,?,?)";assertEquals(eSql,sSql.toString());assertEquals(eTpl,sSql.toTemplate());}public void testSimpleSql(){String eSql="INSERT INTO users (no,id,name,gender,height) VALUES(1,15666662656565,'johny',null,195.36)";String eTpl="INSERT INTO users (no,id,name,gender,height) VALUES(?,?,?,?,?)";LikeSql iSql=DML.insertInto("users") .value("no", 1) .value("id", new BigInteger("15666662656565")) .value("name","johny") .value("gender",null) .value("height", 195.36);assertEquals(eSql,iSql.toString());assertEquals(eTpl,iSql.toTemplate());}?
LikeSql sql=DML.selectAll() .from("user") .where(QuestExp.qt("id=? AND gender=?") .set(1, 1) .set(2, 'M'));PreparedStatement stmt=sql.toPreStatement(con);System.out.println("Template:"+sql.toTemplate());System.out.println("SQL:"+sql.toString());ResultSet rs=stmt.executeQuery();while(rs.next()){System.out.println(rs.getString("name"));}?LikeSql不是什么LikeSql不是ORM框架LikeSql不是重复发明iBatis,Hibernate?
为什么会有LikeSql其实最初的想法来源于我工作经手的几个项目,项目都是采用简单的JDBC+直接拼接SQL来访问数据库。直接拼接SQL存在诸多缺点,这里就不在多论述了。主要是我在维护和改进的过程中,发现并没有一个很优雅的方式来处理SQL。我写过两篇文章来讨论过这个问题我使用DSL编写SQL的一个java实现http://www.iteye.com/topic/620906
你还在用PreparedStatement吗http://www.iteye.com/topic/756176
我认为PreparedStatement对比直接拼接SQL并没有绝对的优势,而且它没法解决一些实际的需求,写起来也不能算优雅。于是我开始搜索相关的解决方案,并没有发现一些现存的工具,在读了很多相关的文章,我认为DSL会是一个很好的方式来处理SQL。我在工作的项目当中引入了DSL的思想,写了一个雏形的框架,因为一开始写的时候,设计不是特别完善,于是决定做一个开源的项目,把这个框架重新设计,这就成了LikeSql。
LikeSql的计划
- 尽快完善文档,释出release版本(希望年内达成吧)编写教程和例子建立反馈渠道和讨论圈子和其他框架的集成
?
关于LikeSql的名字?
Like有两层意思,一个相似,像的意思,就是希望这个框架写起来与SQL文本很相近,易读性强;另一个意思是喜欢,希望使用它的用户能够喜欢写SQL。
?
?
欢迎加入这个项目,欢迎指教和讨论。
,因为上述两点.开源框架存在总是有理由的,jdbc的PreparedStatement 出现也是因为实际使用中的要求,这种要求从java出现之前的c时代就有了. ,因为上述两点.
开源框架存在总是有理由的,jdbc的PreparedStatement 出现也是因为实际使用中的要求,这种要求从java出现之前的c时代就有了.
特别说明,避免sql注入的最终手段,不是靠LZ先前文章中所述的过滤类似 update等 关键字就可以解决的,因为这样会有下面的问题:
1.如果本身字段是个varchar的备注域,备注内填写的内容是"update the record",那就会导致要么插入记录异常,要不就变成"**** the record",这不是应用要求的真实表达,当然,LZ现在做的应用是国内的,一般很少会用英文写作.
2.sql注入还有所谓的转义sql注入,请LZ参看相关文档,对于转义sql注入,关键字过滤是苍白的.
市面上所谓的前端sql注入放火墙就存在上面的问题,只是用来忽悠一些人而已,因为这是置标,不是置本的方法.
而PreparedStatement 是避免sql最好最终手段,因为PreparedStatement 里的?告诉了数据库本身,这个?是参数,而不是sql语句的执行部分,就算这个?相对应的参数是"update table set xxx=xx",它也认为这个是字符串而已,不会当作sql语句执行.
所以LZ一直要避免使用PreparedStatement ,就因为它不让你爽,但是如果想通过自己的工具自己组SQL直接执行,就必须面对我前面所说的两个问题,黑客和性能不让你爽,这也是大部分使用广泛的SQL封装工具选用PreparedStatement 的原因.
综上所述,赞同你的钻研精神,但是优雅是要有代价的,而你的工具面临安全和性能的双重约束,如果用在没有安全要求和性能要求的地方也行是可以的,但只要有安全要求,基本就会crack掉.在这种意义上,这种工具反而是有害的.
.所以,综上所述,你的过滤如果不能像数据库本身进行sql解析,判断数据类型是否合法,数据类型和数据库表对应的列数据类型匹配,那在原理上进行sql注入的防范难度是非常高的。当然LZ可以说通过jdbc接口获得每张表的字段类型,那就对有关联的select,如“select a.x,b.y from xx a ,yy b where a.z=? "这种语句 必须自己进行sql解析,执行转义函数,判断,自己建立sandbox进行预执行方才知道该次的参数是否是sql注入的。否则,你就会错误的挡掉下面的sql语句"update a set x='update y set b=1'",这句话的本义是将x列更新为字符串"'update y set b=1y".在LZ的算法中变成如何就不知道是否是认为注入而拒绝了。