#java #multithreading #jdbc #prepared-statement
#java #многопоточность #jdbc #подготовленное заявление
Вопрос:
У меня была рабочая версия многопоточного кода, однако я был недоволен тем, что мой PreparedStatement-wrapperclass не является потокобезопасным. Поэтому я решил сгенерировать PreparedStatements в a ThreadLocal
, чтобы сделать оболочку потокобезопасной.
Сразу же на меня начинают обрушиваться SQLExceptions. Основная ошибка Oracle — это ошибка ORA-00060 deadlock detected
, которая, согласно Интернету, должна возникать только в сценариях записи. Все мои утверждения доступны только для чтения. Это происходит в каком-то неясном ACL-пакете, о котором я никогда не слышал и к которому не обращался сознательно.
Я потратил некоторое время и усилия на подготовку и проверку гипотезы, которая заключается в том, что генерация Connection
объекта и подготовка оператора из этого объекта из DataSource
объекта не должны происходить одновременно, потому что управление доступом к базе данных может быть не «потокобезопасным» (хотя источник данных, безусловно, есть). Может кто-нибудь подтвердить или опровергнуть этот вывод?
Если это действительно так, существует ли наилучший способ избежать того, чтобы PreparedStatements генерировались в одно и то же время в многопоточном приложении?
РЕДАКТИРОВАТЬ: Как и было задано в тексте исключения:
Caused by: java.sql.SQLException: ORA-00604: error occurred at recursive SQL level 1
ORA-00060: deadlock detected while waiting for resource
ORA-06512: at "XXX.PKG_ACL", line 129
ORA-06512: at "XXX.PKG_ACL", line 459
ORA-06512: at "XXX.PKG_UTILS", line 1933
ORA-06512: at line 6
Ответ №1:
Может кто-нибудь подтвердить или опровергнуть этот вывод?
Я ничего не слышал в этом роде, и если он существует, это может быть просто деталью реализации. Можете ли вы опубликовать свою трассировку стека (конечно, удалив личную информацию)?
Кроме того, есть ли причина, по которой вы пытаетесь сделать PreparedStatement
потокобезопасным, а не полагаться на пул / кэш подготовленных операторов? Или, более конкретно, какой анализ заставляет вас внедрять ThreadLocal
PreparedStatement
?
Комментарии:
1. У меня есть сценарий с фиксированным набором из n средств доступа к БД, все из которых имеют свои очень личные PreparedStatement для доступа к БД. Я понимаю, что теоретически источник данных должен позаботиться о объединении. Проблема, по-видимому, заключается в том, что одновременная генерация n подготовленных утверждений приводит к тупиковой ситуации в базе данных. Я не пытаюсь сделать оператор потокобезопасным.
Ответ №2:
Оператор принадлежит соединению, и соединение не может использоваться одновременно. Поток обычно должен сначала «владеть» соединением, прежде чем выполнять инструкции для него. Так что просто следуйте идиоме
1 check out connection
2 prepare statement
3 execute query
4 return connection
Вы не можете избежать [1] и [4], они необходимы; в любом случае, не слишком дорого, если их объединить.
Вы хотите кэшировать [2], в этом тоже нет необходимости, драйвер, вероятно, уже выполняет кэширование.
Комментарии:
1. Я не получаю доступ к соединениям многопоточным способом. Код есть (более или менее)
run() {datasource.getConnection().prepareStatement(sql); do_some_stuff()}
. Источник данных является потокобезопасным, но я полагаю, что база данных может быть не «потокобезопасной», несмотря на все, что jdbc делает поверх нее.