Java优化
2013-10-11 17:41
323 查看
效率可以大幅度提升的空间在数据库操作部分以及程序控制部分。下面,分条叙述对耗时操作的改进方法。
关闭日志记录,或者更改日志输出级别。因为从两台服务器的外部系统
D 上获取到的信息是相同的,所以数据库插入操作会抛出异常,异常信息类似于“Attempt to insert duplicate record”,这样的异常信息跟有效信息的条数相等,有上千条。这种情况是能预料到的,所以可以考虑关闭日志记录,或者不关闭日志记录而是更改日志输出级别,只记录严重级别(severe level)的错误信息,并将此类操作的日志级别调整为警告级别(warning level),这样就不会记录以上异常信息了。本项目使用的是 Java 自带的日志记录类,以下配置文件将日志输出级别设置为严重级别。
清单 1. log.properties 设置日志输出级别的片段
共享数据库连接。共有 5 次数据库连接操作,每次都需重新建立数据库连接,数据库插入操作完成之后又立即释放了,数据库连接没有被复用。为了做到共享数据库连接,可以通过单例模式(Singleton Pattern)获得一个相同的数据库连接,每次数据库连接操作都共享这个数据库连接。这里没有使用数据库连接池(Database
Connection Pool)是因为在程序只有少量的数据库连接操作,只有在大量并发数据库连接的时候才需要连接池。
清单 2. 共享数据库连接的代码片段
使用预编译 SQL。
具体做法是使用 java.sql.PreparedStatement 代替 java.sql.Statement 生成 SQL 语句。PreparedStatement 使得数据库预先编译好 SQL 语句,可以传入参数。
清单 3. 使用 Statement 的代码片段
清单 4. 使用 PreparedStatement 的代码片段
使用 SQL 批处理。
使用多线程实现并发 / 并行。
清空数据库表的操作应该先于数据库插入操作完成,可以通过 java.lang.Thread 类的 join 方法控制线程执行的先后次序。在单核 CPU 时代,操作系统中某一时刻只有一个线程在运行,通过进程 / 线程调度,给每个线程分配一小段执行的时间片,可以实现多个进程 / 线程的并发(concurrent)执行。而在目前的多核多处理器背景下,操作系统中同一时刻可以有多个线程并行(parallel)执行,大大地提高了计算速度。
清单 5. 使用多线程的代码片段
使用 DAO 模式抽象出数据访问层。
图 2. DAO 模式的层次结构
清单 6. 使用 DAO 模式的代码片段
通过该项目实例,笔者深深地感到,想要写出一个性能优化、可读性可扩展性强的程序,需要对计算机系统的基本概念、原理,编程语言的特性,软件系统架构设计都有较深入的理解。“纸上得来终觉浅,绝知此事要躬行”,想要将这些基本理论、编程技巧融会贯通,还需要不断地实践,并总结心得体会。
链接:http://www.ibm.com/developerworks/cn/java/j-lo-codeoptimize/
针对日志记录的优化
关闭日志记录,或者更改日志输出级别。因为从两台服务器的外部系统D 上获取到的信息是相同的,所以数据库插入操作会抛出异常,异常信息类似于“Attempt to insert duplicate record”,这样的异常信息跟有效信息的条数相等,有上千条。这种情况是能预料到的,所以可以考虑关闭日志记录,或者不关闭日志记录而是更改日志输出级别,只记录严重级别(severe level)的错误信息,并将此类操作的日志级别调整为警告级别(warning level),这样就不会记录以上异常信息了。本项目使用的是 Java 自带的日志记录类,以下配置文件将日志输出级别设置为严重级别。
清单 1. log.properties 设置日志输出级别的片段
# default file output is in user ’ s home directory. # levels can be: SEVERE, WARNING, INFO, FINE, FINER, FINEST java.util.logging.ConsoleHandler.level=SEVERE java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter java.util.logging.FileHandler.append=true
针对数据库连接的优化
共享数据库连接。共有 5 次数据库连接操作,每次都需重新建立数据库连接,数据库插入操作完成之后又立即释放了,数据库连接没有被复用。为了做到共享数据库连接,可以通过单例模式(Singleton Pattern)获得一个相同的数据库连接,每次数据库连接操作都共享这个数据库连接。这里没有使用数据库连接池(DatabaseConnection Pool)是因为在程序只有少量的数据库连接操作,只有在大量并发数据库连接的时候才需要连接池。
清单 2. 共享数据库连接的代码片段
public class JdbcUtil { private static Connection con; // 从配置文件读取连接数据库的信息 private static String driverClassName; private static String url; private static String username; private static String password; private static String currentSchema; private static Properties properties = new Properties(); static { // driverClassName, url, username, password, currentSchema 等从配置文件读取,代码略去 try { Class.forName(driverClassName); } catch (ClassNotFoundException e) { e.printStackTrace(); } properties.setProperty("user", username); properties.setProperty("password", password); properties.setProperty("currentSchema", currentSchema); try { con = DriverManager.getConnection(url, properties); } catch (SQLException e) { e.printStackTrace(); } } private JdbcUtil() {} // 获得一个单例的、共享的数据库连接 public static Connection getConnection() { return con; } public static void close() throws SQLException { if (con != null) con.close(); } }
针对插入数据库记录的优化 1
使用预编译 SQL。具体做法是使用 java.sql.PreparedStatement 代替 java.sql.Statement 生成 SQL 语句。PreparedStatement 使得数据库预先编译好 SQL 语句,可以传入参数。
清单 3. 使用 Statement 的代码片段
// 需要拼接 SQL 语句,执行效率不高,代码可读性不强 StringBuilder sql = new StringBuilder(); sql.append("insert into table1(column1,column2) values('"); sql.append(column1Value); sql.append("','"); sql.append(column2Value); sql.append("');"); Statement st; try { st = con.createStatement(); st.executeUpdate(sql.toString()); } catch (SQLException e) { e.printStackTrace(); }
清单 4. 使用 PreparedStatement 的代码片段
// 预编译 SQL 语句,执行效率高,可读性强 String sql = “insert into table1(column1,column2) values(?,?)”; PreparedStatement pst = con.prepareStatement(sql); pst.setString(1,column1Value); pst.setString(2,column2Value); pst.execute();
针对插入数据库记录的优化 2
使用 SQL 批处理。
针对多线程的优化
使用多线程实现并发 / 并行。清空数据库表的操作应该先于数据库插入操作完成,可以通过 java.lang.Thread 类的 join 方法控制线程执行的先后次序。在单核 CPU 时代,操作系统中某一时刻只有一个线程在运行,通过进程 / 线程调度,给每个线程分配一小段执行的时间片,可以实现多个进程 / 线程的并发(concurrent)执行。而在目前的多核多处理器背景下,操作系统中同一时刻可以有多个线程并行(parallel)执行,大大地提高了计算速度。
清单 5. 使用多线程的代码片段
Thread t0 = new Thread(new ClearTableTask()); Thread t1 = new Thread(new StoreServersTask(ADDRESS1)); Thread t2 = new Thread(new StoreServersTask(ADDRESS2)); try { t0.start(); // 执行完清空操作后,再进行后续操作 t0.join(); t1.start(); t2.start(); t1.join(); t2.join(); } catch (InterruptedException e) { e.printStackTrace(); } // 断开数据库连接 try { JdbcUtil.close(); } catch (SQLException e) { e.printStackTrace(); }
针对设计模式的优化
使用 DAO 模式抽象出数据访问层。图 2. DAO 模式的层次结构
清单 6. 使用 DAO 模式的代码片段
// DeviceDAO.java,定义了 DAO 抽象,上层的业务逻辑代码引用该接口,面向接口编程 public interface DeviceDAO { public void add(Device device); } // DeviceDAOImpl.java,DAO 实现,具体的 SQL 语句和数据库操作由该类实现 public class DeviceDAOImpl implements DeviceDAO { private Connection con; public DeviceDAOImpl() { // 获得数据库连接,代码略去 } @Override public void add(Device device) { // 使用 PreparedStatement 进行数据库插入记录操作,代码略去 } }
结束语
通过该项目实例,笔者深深地感到,想要写出一个性能优化、可读性可扩展性强的程序,需要对计算机系统的基本概念、原理,编程语言的特性,软件系统架构设计都有较深入的理解。“纸上得来终觉浅,绝知此事要躬行”,想要将这些基本理论、编程技巧融会贯通,还需要不断地实践,并总结心得体会。链接:http://www.ibm.com/developerworks/cn/java/j-lo-codeoptimize/
相关文章推荐
- Java的国际化(i18n)
- Use HibernateTemplate in Spring
- java实现链表
- Java 反射调用的一种优化
- Spring事务配置的五种方式及示例代码
- JAVA设计模式之策略模式
- java中静态代码块的用法 static用法详解
- java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
- Java版的Quartz表达式生成器,同时适用于Quartz.net(免费下载)
- [置顶] SPRING ,HIBERNATE,MYBATIS重构系统(带spring事务测试及spring Restful测试)
- [置顶] SPRING ,HIBERNATE,MYBATIS重构系统
- [置顶] 利用spring mvc,hibernate重构系统(2)
- [置顶] 利用spring mvc,hibernate重构系统(1)
- SPRING MVC上传的中文乱码问题
- DWR与SPRING 集成
- 利用SPRINGMVC3.2改造旧系统
- SPRING MVC3.2案例讲解--异常处理
- SPRING MVC3.2案例讲解-请求重定向与请求转发
- Spring Roo框架开发注意点
- SPRING MVC3.2案例讲解--fileupload