#java #datasource #connection-pooling
#java #источник данных #объединение пулов соединений
Вопрос:
Проблема:
- Программа используется
com.mchange.v2.c3p0.ComboPooledDataSource
для подключения к серверу Sybase - Программа выполняет 2 метода
runSQL1()
иrunSQL2()
последовательно -
runSQL1()
выполняет SQL, который создает #temptableSELECT * INTO #myTemp FROM TABLE1 WHERE X=2
-
runSQL2()
выполняет SQL, который считывает из этого #temptableSELECT * FROM #myTemp WHERE Y=3
-
ПРОБЛЕМА:
runSQL2()
из пула передается другое соединение с БД, отличное от того, которое было переданоrunSQL1()
.Однако Sybase #temptables зависит от соединения, поэтому
runSQL2()
сбой происходит, когда он не может найти таблицу.
Наиболее очевидное решение, которое я могу придумать (помимо вырожденного решения о создании пула размером 1, после чего нам даже не нужен пул), — это каким-то образом запомнить, какое конкретное соединение из пула использовалось runSQL1()
, и runSQL2()
запросить то же соединение.
Есть ли способ сделать это в com.mchange.v2.c3p0.ComboPooledDataSource
?
Если возможно, я хотел бы получить ответ, который безопасен для параллелизма (другими словами, если соединение, используемое в runSQL1(), используется другим потоком, вызов runSQL2() для получения соединения будет ждать, пока это соединение не будет освобождено другим потоком).
Однако, если это невозможно, я согласен с ответом, который предполагает, что все соединения с БД (те, о которых я забочусь) происходят в одном потоке, и поэтому любое соединение, запрошенное runSQL2(), будет доступно на 100%, если оно было доступно для runSQL1() .
Я также приветствую любые решения, которые решают проблему каким-либо другим способом, если они не включают «прекратить использование #temptables» как часть решения.
Комментарии:
1. Почему вы не можете запросить соединение перед запуском part1, а затем передать его в качестве параметра для обоих вызовов?
2. @ivan сделал это. Но мне не нравится это решение, поэтому я хотел бы знать, как получить конкретное соединение вместо этого
3. Я также считаю, что решение, предложенное @Ivan, является правильным решением. Чтобы получить его любым другим способом, вам необходимо сохранить хотя бы идентификатор соединения при его первом получении. После этого вам нужно использовать отражение в менеджерах пулов и найти соответствующее соединение. Вместо этого просто хранить ссылку на конкретное соединение более чисто. Если вам действительно нужно сделать это, запросив идентификатор, вы можете написать свой собственный менеджер соединений-оболочек и использовать его.
4. Что вы делаете со своим
ComboPooledDataSource
? Он должен оставаться открытым на время использования базы данных. Используйте его, чтобы получить из него ваш объект подключения. Если #temptable зависит от определенного соединения, вы можете повторно использовать только то же соединение, с которым вы выполнилиrunSQL1()
. Кроме того, вы пытались создать разделяемую временную таблицу ?
Ответ №1:
Самый простой и очевидный способ сделать это — просто запросить соединение из пула, а затем запустить runSQL1()
и runSQL2()
с этим соединением. Шаблон использования, предлагаемый в вопросе, противоречит общим принципам проектирования менеджеров пулов соединений, поскольку он эффективно продвигает их к какому-то менеджеру транзакций.
Существуют Java-фреймворки, которые могут помочь в этом. Например, весной @Transaction
или TransactionTemplate
может использоваться для разграничения границ транзакций, и это гарантирует, что одно соединение используется одним потоком (или, точнее, в соответствии с аннотациями распространения транзакций). Spring может использовать множество менеджеров транзакций, но, вероятно, проще всего было бы использовать DataSourceTransactionManager, и его также можно настроить для использования c3p0
как DataSource
.