PoEAA笔记-映射到关系数据库-3.7 数据库连接

3.7 数据库连接

通常,一个连接必须在能执行针对数据库的命令之前就打开。实际上,经常需要一个显示连接来建立和执行命令。在命令的整个执行过程中,该连接必须是打开的。查询的结果将返回一个记录集。某些接口提供无连接的记录集,这些记录集在连接关闭之后还能继续使用。其他的接口只提供连接的记录集,这意味着当记录集正在使用的时候连接必须一直打开。如果正在一个事务中运行,经常会把事务绑定在特定的连接上,当它运行的时候这个连接也必须一直打开。

如果必须自己实现连接池,首先就要检查连接池是不是真的能提高性能。越来越多的环境使我们可以更快地创建新的连接,因此不需要缓冲池。

提供连接池的环境经常把连接池放在一个类似创建新连接的接口后面。用这种方法,无需知道得到的是一个新创建连接还是从连接池里面分配的,那样很好,因为是否选择连接池被很好地封装起来。类似地,关闭一个连接可能并没有真关闭它,而只是把它交还给连接池以便别人可以使用。

无论创建连接的代价是高还是低,连接都必须好好管理。因为它们是珍贵的资源,必须在使用完毕时立刻关闭。还有,如果正在进行一次事务,通常需要保证:在这次特定的事务中,每一个命令都是从同一个连接发出的。

最常见的建议就是用一个到连接池或者连接管理器的调用,显示得到一个连接,并且通过它来执行数据库命令,一旦执行完了,立刻把它关闭。这个建议带来两个问题:首先,保证在任何需要的地方都能得到一个连接;其次,保证不会在最后忘记关闭它。

为了保证在任何需要的地方都能得到一个连接,有两种选择。一是把这个连接作为一个直接的参数传递出去。这样做的问题在于这个连接会加入到各种各样的方法调用中去,而它的目的可能仅仅是要传递某个在调用栈中第五层下的方法。当然,这种情况就带出了注册表,因为不希望多个线程使用同一个连接,所以将需要一个线程范围内的注册表。

如果你有我一半那么健忘,显示关闭就不是一个好主意。需要关闭的时候可能很容易就忘了。也不能通过每个命令来关闭连接,因为可能正在一次事务中运行,如果关闭了通常会导致事务回滚。

现代环境提供了自动的内存管理和垃圾回收机制,因此保证连接关闭的一种方法就是使用垃圾回收器。在这种方式下,连接自身或者引用这个连接的对象会在垃圾回收期间关闭连接。这样做的好处是:它使用了和内存管理相同的机制,同样方便,也不陌生。这样做的问题是:连接的关闭只有当垃圾回收器实际收内存的时候才发生,可能离这个连接失去它最后一次引用的时间已经很久了。结果是,未被引用的连接可能会隔一段时间才被关闭。这究竟是不是一个问题要取决于特定的环境。

总的来说,我不喜欢依赖垃圾回收机制。其他的机制,甚至是显示关闭都会好一些。当然,垃圾回收机制在其他机制失败的情况下还是一种很好的后备。毕竟,让连接最终关闭总比让它们一致运行着强

因为事务的完成有一种可见的效果,所以即使是忘了提交,也很容易把它标识出来。工作单元很自然地是用于管理事务和连接。

如果要在事务之外处理一些事情,比如读取不可变数据,可以为每个命令使用一个新建连接。缓冲池可以处理任何创建短周期连接的问题。

如果你正在使用一个断接的记录集,可以打开一个连接,把数据放到记录集中并且正在操纵记录集数据的时候关闭它。这样,数据使用结束以后,就可以打开一个新的连接和事务,把数据写出去。如果这样做,需要防止记录集正在使用的时候数据被修改。这个主题将会在同步控制中讨论。

3.6 其他问题

细心的读者会注意到,一些代码例子用到了select * from的格式,而其他的查询语句使用了已命名的列。对于某些数据库驱动使用select *会带来一些严重的问题,如果加入了新的列或者某个列被重新排序就会失败。尽管更多的现代环境已经没有这个问题,但如果使用位置索引来从列中得到信息,那么选择select *也是不明智的,因为一个列的从新排序同样会导致代码失效。对列名索引使用select *是可以的,并且列名索引更容易读取;然而,列名索引可能比较慢,尽管这也许并不会比SQL调用需要的时间有很大的不同。通常最好是测量一下比较保险。

如果使用列序号索引,需要保证对结果集的访问与SQL语句的定义十分接近,这样它们在列重新排序的时候就不会失去同步。因此,如果使用表数据入口,应该使用列名索引作为结果集,它们将被在入口上运行查找操作的每一段代码使用。通常为每一个使用的数据库映射结构提供简单的创建/读取/更新/伤处的测试用例是值得的。这将有助于找到SQL与代码不同步的情况。

尽量使用已预先编译好的静态SQL,而不是每次都编译动态SQL。大多数平台都会提供SQL的预编译机制。一个重要的规则是避免使用字符串串联起多个SQL查询。

许多环境都提供把多个SQL查询打包到一次数据库调用的能力。对这些例子,我没有这么试过,不过这当然也是产品代码中可以使用的策略,如果做取决于平台。

对这些例子中的连接,我祈求它们可以跟在一个对“DB”对象的调用后,那就是一个注册表。如何得到一个连接将依赖于环境,因此你将用需要做的事情来代替它。我在除了关于并发之外的任何模式中都没有涉及事务。再次提醒,需要时刻考虑到环境的需要。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值