这也是思想的变化,对于反复使用的东西,大家发现了一些规律,就会把它模块化,减少重复操作,提高利用率,减少耦合度,使用更加灵活。
1 DAO模式与Java Bean
DAO --数据库操作对象,Database Access Object 是JDBC下常用的模式,保存数据时它将Java Bean的属性拆分成正确的SQL语句,并保存到数据库中;读取数据时将数据从数据库中读取出来,并通过setter方法设置到Java Bean中。
这里就不一一举例了,很简单创建VO,然后和dao.java去操作数据库,返回java数据结构VO。
jsp或者servlet直接调用dao中方法即可。
这个后续框架会进一步延伸,例如mybatis,dao没有实现类,直接定义接口和xml文件即可。他采用了动态代理,工厂模式等实现了jdbc功能。
2 事务实例:转账
CRUD根据API要求操作即可,但是有个概念却是db操作的核心,事务,也是任何开发人员都会面对的头痛问题,因为各种业务分支或者未知异常,以及各种第三方接口的嵌入,怎么保持事务的原子性,完整性才是至关重要的。
所谓事务很好理解,就是一组操作是一个单元,要不全部成功,要不全部失败。A账户转钱给B账户,A钱扣除,B钱收到增加之后整体才算完成。如果A钱扣除,断网或者程序异常,B账户没有增加响应钱,放到银行系统将是灾难。
想想http协议的三次招手,四次挥手就明白了,就是为了确保传输的可靠性,虽然不是事务。
事务有两个结果:提交–Commit和回滚–Rollback。
public static void insert(String sql) throws SQLException {
//获取connection对象
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection();
connection.setAutoCommit(false);
String sqlStr = "INSERT INTO t_emp ( dept_no, ename, hiredate, sal )\n" +
"VALUES\n" +
"\t( 2, 'Jack', now( ), ? )";
statement = connection.prepareStatement(sqlStr);
for (int i = 0; i < 10; i++) {
statement.setDouble(1, 5000 * i);
statement.addBatch();
}
statement.executeBatch();
statement.close();
connection.close();
connection.commit();
} catch (ClassNotFoundException e) {
connection.rollback();
e.printStackTrace();
} catch (SQLException e) {
connection.rollback();
e.printStackTrace();
}
}
我们看到JDBC操作是非常简单的
- connection.setAutoCommit(false);
- connection.commit();
- connection.rollback();
3 存取二进制数据
除了能存储文本、数字、日期等数据,数据库还可以存储二进制数据。
可以把InputStream流数据作为参数设置到blob中,实事上没有这么干的。存文件可以用附件平台或者s3.
用户数据库存存二进制文件没多少意义。
4 数据源 -连接池
jdbc编程中,每次操作一次数据库,都会经过下面过程:
- 创建Connection
- 创建Statement对象
- 获取ResultSet对象
- 销毁ResultSet对象
- 销毁Statement对象
- 断开Connection
即每操作一次数据库,都会创建连接、断开连接。
在实际应用中,创建与断开Connection都会消耗一定的时间、IO资源,在大量的并发访问时尤其明显。为了避免频繁的创建、断开数据库连接,工程师们提出了数据源技术-Data Source,也称作连接池–DBCP,Datebase Connection Pool。
要操作数据库时,程序并不是直接创建Connection,而是向连接池“申请”一个Connection。如果连接池中有空闲的Connection,则返回该Connection,否则创建新的Connection。使用完毕Servlet会释放该Connection。连接池会将该Connection回收并且交给其他的线程使用。
数据源一般实现自javax.sql.DataSource接口。Spring、Struts、Hibernate等框架都有自己的数据源实现,Tomcat中也内置了数据源支持。Tomcat使用Jakarta-Commons Database Connection Pool作为数据源实现,使用时只需要按照tomcat文档配置即可。
存量系统有些数据源确实配置了在了tomcat,这是违规的,因为账号密码连接串暴露了,使用数据源必须加密,不能存储可见
<Context cookie="true">
<!-- Default set of monitored resources. If one of these changes, the -->
<!-- web application will be reloaded. -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>WEB-INF/tomcat-web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
<!-- Uncomment this to disable session persistence across Tomcat restarts -->
<!--
<Manager pathname="" />
-->
<Resource
name="jdbc/databaseWeb"
auth="Container"
type = "javax.sql.DataSource"
maxActive="100"
maxIdle="30"
maxWait="10000"
username="dev"
password="hcgk*2020"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/dev?serverTimezone=GMT%2B8"
/>
</Context>
数据源可以配置在tomcat/conf/server.xml中,也可以配置在tomcat/conf/context.xml中。需要MYSQL驱动放到Tomcat全局lib里下面,而不能放在本web应用下面。
然后要在web程序的web.xml中配置数据源引用,这样才能在Web程序中使用该数据源。
<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/databaseWeb</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
public static Connection getConn() throws ClassNotFoundException, SQLException {
Connection connections = null;
try {
// 实例化一个InitialContext
Context initContext = new InitialContext();
// 获取所有的资源
Context envContext = (Context) initContext.lookup("java:/comp/env");
DataSource ds = (DataSource) envContext.lookup("jdbc/databaseWeb");
// 获取JNDI数据源
connections = ds.getConnection();
} catch (NamingException e) {
e.printStackTrace();
}
//返回连接对象
return connections;
}