动态识别区分数据库

实际工作中,生产、开发和测试都有各自的数据库,为了更方便地部署和运行程序,最好在代码里实现好动态识别+连接数据库的功能。首先,在创建artifact的时候用MyAppLive, MyAppDev和MyAppTest做artifact的名字,用来区分生产、开发和测试环境下的代码。然后,Java Servlet提供的ServletContext.getContextPath()可以用来确认artifact的名字。最后,根据名字建立相应的数据库连接。

用文件管理数据库的配置

为了进一步将配置环境的工作和代码解耦合,所有配置信息都可以放在独立的文件中,将来如需修改设置,只需要修改文件即可,不需要动源代码。读取的时候只需:Properties props = java.util.Properties.load(new FileInputStream(File configFile));

连接池

Tomcat提供了org.apache.tomcat.jdbc.pool.DataSource用来管理连接池。

// create a pool
DataSource dataSource = (DataSource) (new DataSourceFactory().createDataSource(props));

// get a connection
Connection conn = dataSource.getConnection(autocommit=false);

// put back the connection
conn.close();

编码问题

创建表的时候指定字符集而不是依赖默认值。

create table if not exists (
	....
) engine = InnoDB 
default charset = utf8;

在连接数据库时也可以在url中加入locale参数,比如jdbc:mysql://127.0.0.1:3306/db_dev?useEncoding=true&characterEncoding=UTF-8

Prepared Statement

PreparedStatement会提升数据库的查询速度,原因是数据库会先验证查询语句的有效性(validity),之后才会真正执行该语句。使用PreparedStatement之后,数据库只会验证一次有效性,之后的每一次会直接把参数填到相应的位置,然后执行。

从代码设计角度讲,首先,MySQL语句可以用工厂模式批量生成,然后遍历每条MySQL Statement并执行executeQuery()或executeUpdate(),最后得到ResultSet结果集。

关闭数据库

首先,需要关闭连接池。其次,注销驱动。如果只关闭连接池而不注销驱动,很容易造成JDBC内存泄漏。最后,清理线程。

// close connection pool
dataSource.close(); 
dataSource = null; // to prevent shutdown twice. 

// deregister driver
DriverManager.deregisterDriver(DriverManager.getDriver(String databaseConnectionUrl));

// clean up threads
com.mysql.jdbc.AbandonedConnectionCleanupThread.shutDown();