Технический стек:
- Tomcat 7.0.47
- Spring 4.3.8
- SQL Server 2012
Я пытаюсьреализовать пул соединений с БД в моем веб-приложении на Java, и хотя я этого добился, при выполнении операторов SQL я обнаружил некоторые несоответствия.
Я попробовал 2 разных подхода, но безуспешно, надеюсь, вы сможете обеспечитьлюбая подсказка:
1 ° - ресурс JNDI Tomcat
Несмотря на то, что мой пул соединений работает, я потерял функциональность, когда использовал структуры в качестве параметров в callableStatement, выбрасывая исключение приведения из Proxy $ 14 в SQLServerCallableStatement, проблема, которая не возникаетпредставить с обычным источником данных.Я заметил, что
jdbcInterceptors="ConnectionState;StatementFinalizer;SlowQueryReport(threshold=1500);"
- Произошло исключение Cast и пул JNDI работает нормально.
jdbcInterceptors="ConnectionState;StatementFinalizer;"
- Исключение не Cast, но параметр Structure игнорируется, и пул JNDI работает нормально.
jdbcInterceptors="
- Параметр структуры работает нормально, но в подключении к пулу JNDI исчерпаны доступные подключения.
это моя конфигурация:
Tomcat server.xml
<Resource name="jdbc/TomcatDS"
global="jdbc/TomcatDS"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
auth="Container"
type="javax.sql.DataSource"
username="user"
password="pass"
driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
description="SQLServer DB DS"
url="jdbc:sqlserver://<host>:1433;DatabaseName=<DB>;schema=dbo;encrypt=true;trustServerCertificate=true;"
maxActive="50"
maxTotal="50"
maxIdle="50"
minIdle="10"
maxWait="15000"
reomoveAbandoned="true"
removeAbandonedTimeout="3000"
defaultAutoCommit="true" jdbcInterceptors="ConnectionState;StatementFinalizer;SlowQueryReport(threshold=1500);"/>
web.xml
<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/TomcatDS</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
context.xml
<Context path="/">
<ResourceLink name="jdbc/TomcatDS" global="jdbc/TomcatDS" type="javax.sql.DataSource"/>
</Context>
spring-db-config.xml
<bean id="sqlServerDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/TomcatDS"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" abstract="true">
<property name="dataSource">
<ref bean="sqlServerDataSource" />
</property>
</bean>
2 ° - Spring DataSource с использованием Tomcat DBCP jar
При таком способе соединение с пулом соединений работает странно, и хотя исключений не происходитчто я еще не решил, так это то, что соединения не освобождаются в пул, вместо этого они однозначно закрываются, пока в моем приложении не закончатся соединения.(Отключенный JNDI)
Моя конфигурация:
spring-db-config.xml
<bean id="sqlServerPoolDataSource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
<property name="username" value="user"/>
<property name="password" value="pass"/>
<property name="url" value="jdbc:sqlserver://<host>:1433;DatabaseName=<DB>;schema=dbo;encrypt=true;trustServerCertificate=true;"/>
<property name="maxActive" value="50"/>
<property name="maxIdle" value="50"/>
<property name="minIdle" value="10"/>
<property name="maxWait" value="15000"/>
<property name="removeAbandoned" value="true"/>
<property name="removeAbandonedTimeout" value="3000"/>
<property name="defaultAutoCommit" value="true"/>
<property name="jdbcInterceptors" value="ConnectionState;StatementFinalizer;"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" abstract="true">
<property name="dataSource">
<ref bean="sqlServerPoolDataSource" />
</property>
</bean>
DAO.java
Этот код выполняется при окончательной попытке блока каждого вызова БД.
public void terminateDBCall(ResultSet rs, CallableStatement cstmt) {
if (cstmt != null) {
try {
if (cstmt.getConnection() != null && !cstmt.getConnection().isClosed()){
cstmt.getConnection().close();
}
cstmt.close();
cstmt = null;
} catch (SQLException ex) {
logHandler.registerSystemEvent(this.getClass(), Constants.SystemLogEvent.ERROR, "La session de base de datos no pudo ser cerrada", ex);
}
}
if (rs != null) {
try {
rs.close();
rs = null;
} catch (SQLException ex) {
logHandler.registerSystemEvent(this.getClass(), Constants.SystemLogEvent.ERROR, "El ResultSet no pudo ser cerrado", ex);
}
}
}
Код, который вызывает исключение приведения
@Override
public boolean updateUser(User userVO) {
boolean resultFlag = false;
CallableStatement cstmt = null;
ResultSet rs = null;
try {
SQLServerDataTable sourceDataTable = new SQLServerDataTable();
sourceDataTable.addColumnMetadata("plantaId", java.sql.Types.INTEGER);
for (FactoryValueObject factoryVO : userVO.getFactoryList()) {
sourceDataTable.addRow(factoryVO.getFactoryId());
}
cstmt = getCallableStatement("UPDATE_USER");
cstmt.setInt("UsuarioId", userVO.getUserId());
cstmt.setNString("Usuario", userVO.getUserName());
cstmt.setNString("Password", userVO.getUserPassword());
cstmt.setInt("RolId", userVO.getRoleId());
cstmt.setNString("Email", userVO.getEmail());
cstmt.setInt("Activo", (userVO.isActiveFlag() ? 1 : 0));
cstmt.setNString("ModificadoPor", userVO.getUpdatedBy());
=====> ((SQLServerCallableStatement) cstmt).setStructured("ListaPlantaIds", "dbo.ID_PLANTAS_ASIGNADAS", sourceDataTable);
cstmt.execute();
rs = cstmt.getResultSet();
rs.next();
resultFlag = rs.getInt("resultFlag") == 1;
if(!resultFlag)
logDataBaseError(rs);
logHandler.registerSystemEvent(this.getClass(), Constants.SystemLogEvent.DEBUG, "The user ID: " + userVO.getUserId() + " has been updated!");
} catch (Exception ex) {
logHandler.registerSystemEvent(this.getClass(), Constants.SystemLogEvent.ERROR, ex.getMessage(), ex);
} finally {
terminateDBCall(rs, cstmt);
}
return resultFlag;
}
java.lang.ClassCastException: com.sun.proxy.$Proxy14 cannot be cast to com.microsoft.sqlserver.jdbc.SQLServerCallableStatement