自从数据须要被持久化存储,程序与数据库之间的交互就是不可避免的操做。而早期程序与不一样的数据库的交互方式不一样,意味着程序开发不得不面对数据库的具体实现,一旦切换数据库,又是新的学习过程,这样开发人员的效率始终被和数据库的交互所限制。html
根据软件设计中的依赖倒置原则,要针对接口编程,不要针对实现编程,于是因为数据库的变化而引发实现的变化是违背软件设计的基本原则的。优化的方式是在数据库上提供一层抽象接口,不一样数据库根据接口完成本身的实现,而用户使用时,只需面向接口编程,而不用关心内部的实现细节。若是须要更换数据库,只须要要指定不一样的数据库标识便可。java
Java的JDBC(Java DataBase Connectivity)就是一组这样的抽象API,经过执行SQL语句,为多种关系型数据库提供统一访问。下面以mysql的一个简单查询为例,介绍JDBC的接口和基本构成。mysql
try { // 装载驱动 Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } // 数据库链接 Connection conn = null; // sql执行对象 Statement statement = null; // 结果集 ResultSet resultSet = null; try { // 获取mysql数据库链接 conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/lichao", "root", "root"); // 建立sql执行对象 statement = conn.createStatement(); // 执行sql,返回结果集 resultSet = statement.executeQuery("select * from user"); // 遍历结果集,获取数据 while(resultSet.next()){ Long id = resultSet.getLong("id"); String name = resultSet.getString("name"); Integer age = resultSet.getInt("age"); System.out.println("User[id=" + id + ",name=" + name + ",age=" + age + "]"); } } catch (SQLException e) { e.printStackTrace(); } finally { // 关闭各类资源 if(resultSet!=null) try { resultSet.close(); } catch (SQLException e) { e.printStackTrace(); } if(statement!=null) try { resultSet.close(); } catch (SQLException e) { e.printStackTrace(); } if(conn!=null) try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } }
connection,官方文档的定义是程序员
A connection (session) with a specific database. SQL statements are executed and results are returned within the context of a connection.sql
链接即一个特定数据库的会话,在一个链接的上下文中,sql语句被执行,而后结果被返回。数据库
经过getMetaData方法能够获取数据库中描述的表的信息,支持的sql语法,存储过程以及这个链接的其余性能和能力。apache
setSchema和setCatalog指定数据库具体的catalog或schema,setReadOnly设置链接是否为可读模式,setTypeMap指定字段类型和java类的映射关系(若是为空集合,会覆盖原有映射map),setNetworkTimeout则是等待数据库返回的超时时间,setHoldability改变ResultSet在commit以后的Cursor是否关闭。编程
一个Connection对象中,包含的信息很是之多。在平常开发中,最常接触到的仍是事务相关的操做。api
事务(Transaction),解决的是多个操做执行时,同时成功或同时失败的问题。好比银行转帐时,扣减A的资金和增长B的资金必须一块儿发生,否则银行就干不下去了。session
可是事务的存在,在多用户同时访问相同的数据时会产生冲突。可能出现如下几种不肯定状况:
更新丢失
两个事务同时更新一行数据(事务都未提交),一个事务对数据的更新把另外一个事务对数据的更新覆盖了。
脏读
一个事务读到了另外一个事务未提交的数据操做结果(未提交的数据可能会被回滚)
不可重复读
一个事务对同一行数据重复读取两次,可是却获得了不一样的结果。包括两种状况:
为了解决上述状况,标准sql规范中,定义了4个事务隔离级别,不一样的隔离级别对事务的处理不一样。
隔离级别越高,越能保证数据的完整性和一致性,可是对并发性能的影响也越大。
JDBC中,一个connection被建立时,默认是auto-commit模式,也即一个sql statement做为一个事务,执行完成后自动commit。若是支持多个statement组成一个事务,则要禁止auto-commit模式。
con.setAutoCommit(false);
Connection支持了标准的四种隔离级别,若是没有设置,则查询数据库的默认隔离级别,也能够用setTransactionIsolation方法手动设置。
conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
Connection使用commit和rollback方法支持事务的提交和回滚。
try { conn.setAutoCommit(false); // -- do query and update operation conn.commit(); } catch (Exception e) { conn.rollback(); }
同时使用setSavepoint和releaseSavepoint方法支持保存点的设置和释放。
try { conn.setAutoCommit(false); // -- update 1 Savepoint s1 = conn.setSavepoint(); try { // -- update2 } catch (Exception e) { conn.releaseSavepoint(s1); } conn.commit(); } catch (Exception e) { conn.rollback(); }
DataSource表示一种建立Connection的工厂,在jdk 1.4引入,相对DriverManager的方式更优先推荐使用DataSource。支持三种实现类型:
基于DataSource产生了两个很是经常使用的数据库链接池框架:DBCP和C3P0,解决了数据库链接的复用问题,极大地提升了数据库链接的使用性能。看一个DBCP的简单用例:
BasicDataSource basicDataSource = new BasicDataSource(); basicDataSource.setDriverClassName("com.mysql.jdbc.Driver"); basicDataSource.setUrl("jdbc:mysql://localhost:3306/lichao"); basicDataSource.setUsername("root"); basicDataSource.setPassword("root"); // 初始化链接数 basicDataSource.setInitialSize(5); // 最大链接数 basicDataSource.setMaxActive(30); // 最大空闲链接数 basicDataSource.setMaxIdle(5); // 最小空闲链接数 basicDataSource.setMinIdle(2); Connection conn = basicDataSource.getConnection(); // sql operation conn.close();
关于DBCP和C3P0,具体的这里就不深刻了。
JDBC解决了面向不一样数据库的统一接口问题,咱们只要遵照它的接口编程,则不用关心底层数据库的内部实现。然而程序员对编程便捷的追求是永不止步的。咱们不能接受一次简单的查询须要如此多的步骤,打开链接,建立statement对象,解析结果集,最后关闭资源,甚至连JDBC我都不想关心。个人需求很简单,就是提出一个对数据库的请求(请求或更新),返回给我结果,若是是查询,直接映射到java对象最好。咱们但愿更多地关注真正关心的东西(好比业务),而不是数据的传输过程。因而就出现了各类对JDBC的封装框架,好比apache的dbutils。
参考文档: