Глава 3. Объектные модели и реляционные базы данных 77
вызовов на несколько уровней ниже, а присутствует во всевозможных вызовах методов.
В этой ситуации целесообразно вспомнить о реестре (Registry, 495). Поскольку вам на-
верняка не хочется, чтобы соединением пользовались несколько вычислительных пото-
ков, необходимо применять вариант реестра уровня одного потока.
Даже если вы не так забывчивы, как я, то и в этом случае согласитесь, что требование
явного закрытия соединений довольно обременительно, поскольку его слишком легко
оставить без внимания, что, разумеется, недопустимо. Соединение нельзя закрывать и
после выполнения каждой команды, так как первая же попытка сделать подобное внутри
транзакции приведет к ее откату.
Оперативная память, как и соединения, относится к числу ресурсов, которые надле-
жит возвращать системе сразу по завершении их использования. В современных средах
разработки управление памятью и функции сборки мусора осуществляются автоматиче-
ски. Поэтому один из способов закрытия соединения состоит в том, чтобы довериться
сборщику мусора. При таком подходе соединение закрывается, если в ходе сборки мусо-
ра утилизируются объект соединения как таковой и все объекты, которые на него ссыла-
ются. Удобно то, что здесь применяется та же хорошо знакомая схема управления па-
мятью. Однако есть и проблема: соединение закрывается только тогда, когда сборщик
мусора действительно утилизирует память, а это может произойти гораздо позже, чем ис-
чезнет последняя ссылка, адресующая объект соединения, т.е. в ожидании закрытия он
проведет немало времени. Возникнет подобная проблема или нет, во многом определяется
особенностями среды разработки, которой вы пользуетесь.
Если рассуждать в более широком смысле, я не стал бы слишком полагаться на меха-
низм сборки мусора. Другие схемы — даже с принудительным закрытием соединений —
кажутся более надежными. Впрочем, сборку мусора можно считать своего рода страхо-
вочным вариантом: как говорится, лучше позже, чем никогда.
Поскольку соединения логически тяготеют к транзакциям, удобная стратегия управ-
ления ими состоит в трактовке соединения как неотъемлемого "атрибута" транзакции:
оно открывается в начале транзакции и закрывается по завершении операций фиксации
или отката. Транзакции известно, с каким соединением она взаимодействует, и потому
вы можете сосредоточиться на транзакции, более не заботясь о соединении как таковом.
Поскольку завершение транзакции обычно имеет более "видимый" эффект, чем завер-
шение соединения, вы вряд ли забудете ее зафиксировать (а если и забудете, то, поверьте
мне, быстро об этом вспомните). Один из вариантов совместного управления транзак-
циями и соединениями демонстрируется в типовом решении единица работы (Unit of
Work, 205).
Если речь идет о выполнении операций вне транзакций (например, о чтении заве-
домо неизменяемых данных), для каждой операции можно использовать "свежий"
объект соединения. Совладать с любыми проблемами, касающимися использования
объектов соединений с короткими периодами существования, поможет схема органи-
зации пула соединений.
При необходимости обработки данных в автономном режиме в контексте множест-
ва записей можно открыть соединение для загрузки информации в структуру данных,
закрыть его и приступить к обработке. По завершении следует открыть новое соедине-
ние, активизировать транзакцию и сохранить результаты в базе данных. Если действо-
вать по такой схеме, придется позаботиться о синхронизации данных с той информа-
цией, которая изменялась другими транзакциями в период обработки содержимого