我有自己的DAO,它扩展了NamedJdbcDaoSupport
。这个DAO是使用Spring框架创建的。
我编写了一个小型测试应用程序,可以从主线程多次访问DAO而无需等待。
在这种情况下一切正常。
但是如果我从不同的线程访问DAO,我收到以下NPE:
java.lang.NullPointerException
at org.springframework.jdbc.core.PreparedStatementCreatorFactory$PreparedStatementCreatorImpl.createPreparedStatement(PreparedStatementCreatorFactory.java:238)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:627)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:684)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:711)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:761)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:192)
at test.DAO.loadData(DAO.java:29)
at test.Application$1.run(Application.java:19)
at java.lang.Thread.run(Unknown Source)
在NamedJdbcDaoSupport的描述中有以下注释:
“注意:配置后,此类的实例是线程安全的。”
那我为什么要收到这个NPE?如果我进入Spring源代码,我可以看到DBConnection似乎是null。但为什么?通常,如果Spring无法从连接池获得连接,则返回SQLException。所以永远不可能有NPE。
有人可以帮助我理解为什么NamedJdbcDaoSupport不是线程安全的,尽管有其他意见。我能做什么?
这是我的申请:
public class Application {
public static void main(String[] args) {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("ServerContext.xml");
DAO bean = (DAO)classPathXmlApplicationContext.getBean("dao");
for (int i = 0; i < 100; i++) {
new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 100; j++) {
bean.loadData();
}
}
}).start();
}
}
}
这是我的gradle脚本:
repositories {
mavenCentral()
}
dependencies {
compile group: 'org.springframework', name: 'spring-context', version: '4.3.11.RELEASE'
compile 'org.springframework:spring-jdbc:4.3.11.RELEASE'
compile 'commons-dbcp:commons-dbcp:1.4'
compile files('lib/ojdbc6.zip')
}
这是我的DAO:
public class DAO extends NamedParameterJdbcDaoSupport {
public List<String> loadData() {
Date fromDate = null;
Date toDate = null;
MapSqlParameterSource namedParameters = new MapSqlParameterSource();
namedParameters.addValue("fromDate", fromDate);
namedParameters.addValue("toDate", toDate);
String sql = "SELECT * FROM myTable";
return getNamedParameterJdbcTemplate().query(sql, namedParameters, new RowMapper<String>() {
@Override
public String mapRow(ResultSet rs, int rowNum) throws SQLException {
return null;
}
});
}
}
这是我的春天背景:
<!-- Database -->
<bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close">
<property name="URL" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
<property name="user" value="user"/>
<property name="password" value="passwort"/>
<property name="connectionCachingEnabled" value="true" />
<property name="connectionCacheName" value="my_connection_pool" />
<property name="connectionCacheProperties">
<value>
MinLimit: 10
MaxLimit: 10
InitialLimit: 10
ValidateConnection: true
</value>
</property>
</bean>
<bean id="dao" class="test.DAO">
<property name="dataSource" ref="dataSource"/>
</bean>