因为在做持久层工具开发,现总结一下各种SQL的写法,也算是清晰一下自已的思路:
第一种写法
public void someMethod(){
try
Connection conn=...;
conn.setAutoCommit(false);
PreparedStatement pst=...;
ResultSet rs= executeSomeSql("some sql...");
conn.commit();
} catch (SQLException ex) {
doSomething();
} finally {
close(rs);
close(pst);
close(conn)
}
最基础的JDBC用法,从connectin的获取,事务的开启、提交,rs、st、connection的关闭全部照顾到
优点:100%掌控所有细节。
缺点:过分繁琐,不推荐业务开发中使用
支持第一种写法的工具类:JDK自带。
第二种写法
public void someMethod(Connection conn) throws SQLException {
queryRunner.executeSQL(conn, "some sql...",参数1, 参数2...);
}
将connection作为参数传递, 业务方法不再负责connection的关闭。
优点:业务方法可以简化到一条语句,极大简化了编程。
缺点:必须另外有一个总的方法进行导常处理和关闭connection,connection作为业务方法的参数传入是对业务方法的入侵。
支持第二种写法的工具类:DbUtils。
第三种写法
QueryRunner queryRunner=new QueryRunner(dataSource);
public void someMethod() throws SQLException {
queryRunner.executeSQL("some sql...",参数1, 参数2...);
}
不再将connection作为参数传递, 工具类构造时将DataSource实例注入,SQL方法完成后Connection自动关闭。
优点:业务方法可以简化成一条语句,没有connection参数入侵业务方法。
缺点:如没有第三方服务支持,事务不太好控制,SQLException异常的抛出也是一种入侵,还是需要另一个方法来捕获。
代表作:DbUtils。
第四种写法
DbPro dbPro=new DbPro(dataSource);
public void someMethod(){
dbPro.executeSQL("some sql...",参数1, 参数2...);
}
业务方法没有Connection参数传入,也不会抛出SQLException异常,工具类将SqlException转化为运行时异常抛出。
优点:业务方法没有受到入侵(严格来说dbPro变量的存在也是对业务方法的一种极轻度的入侵,影响业务方法的可移植性),无须关心异常,运行时异常通常不必处理,由事务服务捕获并回滚。
缺点:无明显缺点,但是要引入IOC/AOP工具如Spring等,以捕获切面的方式实现对异常处理、事务处理及Connection的关闭的支持。
代表作:Spring-JDBC、DbUtils-Pro
以上是从对connection关闭、异常处理和事务处理的角度来看的,从以下写法将开始研究对SQL本身写法的优化:
第五种写法
DbPro dbPro=new DbPro(dataSource);
public void someMethod(){
dbPro.executeSQL("sql piece1",param0(参数1),"sql piece2", param(参数2),"sql piece3",param(参数3)...);
}
将参数利用ThreadLocal暂存,从而可以将参数织入到SQL的任意位置,详见"一种将SQL包装成PrepraredStatement的方法"(
http://www.iteye.com/topic/1145415),
优点:1)如果字段名用Java方法或常量代替,则可以实现让普通的SQL支持重构。
2)参数多的SQL,可以保证占位符与实际参数相邻,利于维护。例如下面这种写法,比起传统的JdbcTemplate将所有参数放在方法未尾传递的方式,在可维护性上要好很多:
DbPro.execute("update user set", //
" username=?", param0("Bill"), //
",age=?", param("23"), //
",address=", question("Tianjing"), //
" where id=", question(5));
缺点:重复的参数也必须重复注入; ThreadLocal变量有可能互相干拢,例如不能在一个SQL方法中嵌套另一个SQL调用;
代表作:DbUtils-Pro (或jSqlBox, 其内核基于DbUtils-Pro)
第六种写法
public void someMethod(){
put0("name","张三");
user.setAddress("BeiJing");
put("user",user);
dbPro.executeSQL("update users set name=#{name}, address=#{user.address}");
或 dbPro.executeSQL(findSQL("someSqlID"));
}
利用模板来统一存放SQL,模板的形式可以为XML、文本或Java字符串、Java Annoation、JVM语言如Groovy甚至Java注释(见
https://my.oschina.net/drinkjava2/blog/892309)),另外使用模板也可用第5种方法介绍过的利用ThreadLocal赋值。
优点:便于统一管理SQL,尤其是一些长SQL
缺点:模板不支持重构,参数的赋值和实际的SQL有时存放在两个文件里,而IDE又不支持导航定位,维护不方便。占位符的存在和赋值要多打几个字。
代表作:MyBatis, BeetlSql, DbUtils-Pro, NamedParameterJdbcTemplate
以下写法开始,引入了ORM概念,从SQL角度来看,ORM也可看成一种写SQL的写法。ORM主要分两大部分:1)Java Bean与数据库表的映射 2)Bean之间关联关系与数据库表关联关系的映射
ORM框架林林总总:
从功能来区分,有些简单到只有Bean到数据表的映射如Memory;有些只支持单向的关联映射如MyBatis/BeetlSql/jSqlBox, 有些是全功能的支持复杂的对象-数据库双向关联关系映射如Hibernate,
从是否支持配置来区分,有些是零配置的(如Memory/jFinal-Dao/DbUtils),映射关系靠命名约定来保证, 有些是固定配置的,一旦配置好就不能再变动(MyBatis/Hibernate/JPA/BeetlSQL)。有些支持运行期动态调整配置(如jSqlBox)。
从配置方式来区分,有写在XML中(MyBatis),有写在注解中(Hibernate/JPA/BeetlSQL),有写在Java方法里(jSqlBox)
第七种写法
public void someMethod(){
Session session = getSessionFromSomeWhere();
User user = new user();
user.setName("张三");
session.save(user);
}
优点:CRUD操作非常方便
缺点:对复杂SQL无能为力;session变量的存在对业务方法是一种轻度入侵,当session的功能设计的很复杂,方法很多时,就变成了重度入侵,严重影响业务方法的可移植性。
代表作:Hibernate, MyBatis, BeetlSql
第八种写法
public void someMethod(){
User user = new user();
user.setName("张三");
user.save();
}
又被称为ActiveRecord模式,业务方法中没有session变量出现,
优点:CRUD操作非常方便, 业务方法更简炼
缺点: 对复杂SQL无能为力;Java8以下要实现这种写法,必须让实体类继承于一个基类,占用了唯一的单继承,这也是一种(大多数情况下无关紧要的)入侵。Java8情况要好一些,只需要声明实现接口即可。
代表作:jFinal-Dao, jSqlBox 以及所有基于ActiveRecord模式的持久层工具
第九类写法
严格来说,这不是一种写法,而是一大类五花八门的写法,它往往是专有的,仅适用于各自的框架,例如Hibernate的HQL语言,Hibernate以及Nutz的用Java方法来代替SQL语法,Spring Boots用方法名代替SQL,各种模板对SQL语法的扩充,jSqlBox的利用ThreadLocal暂存映射配置等,如果你看到什么新奇的SQL写法,都归到这一大类吧,第九类写法并不都优于前面8种写法,只是不太好归类而已,甚至个人认为有些是反模式,如HQL和用Java方法代替SQL语法等。
具体在开发中个人优先推荐使用第5、6、8种写法。
另外文中提到的DbUtils-Pro还处于开发阶段,它是一个继承于DbUtils的小项目,欢迎有兴趣者加入。
分享到:
相关推荐
1. **描述一下“Java中面向对象几个典型的面向对象特性”?** - **封装**: 封装是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类提供的公共(public)方法来实现对内部信息的操作...
Java 8中的Lambda表达式允许开发者创建简洁的匿名函数,这些函数可以作为方法参数或者存储在变量中。这种新的编程范式让Java更加现代化,也使得开发者能够更好地处理集合操作、I/O操作以及并发编程等问题。 #### 二...
**九、总结** 通过以上步骤,我们成功地使用Hibernate实现了DAO层的封装,使得数据库操作更加规范、易于维护。在实际项目中,可以根据需求进一步优化,比如引入Spring Data JPA,或者使用MyBatis等其他持久化框架,...
如:prod_price="" 这种写法是错的(不要受到corejava的影响) prod_price=NULL 这种写法是错的(不要受到corejava的影响) prod_price IS NULL 这种写法才是对的 NVL:处理空值,把空值转化为指定值。可转化为日期、...
Java是一种广泛使用的面向对象的编程语言,以其平台独立性、丰富的类库和高效性能而闻名。这份"java 学习笔记大全"包含了深入学习Java所需的关键知识点,无论你是初学者还是经验丰富的开发者,都能从中受益。 一、...
**描述:** JavaBean是一种标准的Java对象,用于封装数据。不当使用JavaBean会导致数据无法正确传递或读取。 **解决办法:** - 确认JavaBean的属性是否正确设置,包括getter和setter方法。 - 在DAO层和服务层正确地...
《阿里巴巴Java开发手册终极版》是Java开发者的重要参考资料,它由阿里巴巴集团的资深技术专家团队编写,旨在规范Java开发过程中的编码习惯,提高代码质量和团队协作效率。本手册覆盖了从基本语法到高级特性的全面...
6. **JSP与Servlet的关系**:JSP本质上是Servlet的一种简化写法,JSP文件会被JSP引擎转换成Servlet源码,再编译成Servlet类执行。 【SQL Server 2005数据库系统】 SQL Server 2005是微软公司推出的一款关系型...
Java Database Connectivity (JDBC) 是一套用于执行 SQL 语句的 Java API,它可以为多种关系型数据库提供统一访问,它由一组用 Java 编程语言编写的类和接口组成。JDBC 提供了一种基准机制,无论哪种数据库被访问,...
3. **JSP内置对象**:JSP提供了九大内置对象,如`request`、`response`、`session`、`application`等,它们是Java Servlet API中的对象,可以直接在JSP页面中使用,极大地简化了开发工作。 4. **会话管理**:在聊天...
2. **JSP脚本元素**:讲解`<scriptlet>`、`<expression>`和`<declaration>`三种脚本元素的用途,以及如何在JSP页面中编写Java代码。 3. **JSP指令**:详细解释`<%@ page>`、`<%@ include>`和`<%@ taglib>`指令,...
JPQL (Java Persistence Query Language) 是一种面向对象的查询语言。在使用 JPQL 编写查询时,Spring Data JPA 会自动将其转换为 SQL 查询执行。这种转换大大简化了查询语句的编写,并且提供了更好的可读性。 ####...
该引擎不仅适用于 Web 应用开发,还广泛应用于多种场景,如 SQL 和 PostScript 的生成、源代码及报告的创建等。它甚至可以作为其他系统的组件集成使用。 #### 二、变量 ##### 1. 变量定义 在 Velocity 中,变量...