使用SpringJDBC的PreparedStatementCreator的正确方法是什么?
根据我的理解,在Java中使用PreparedStatement是因为我们可以多次使用它。 但是我对使用SpringJDBC的PreparedStatementCreator有些困惑使用SpringJDBC的PreparedStatementCreator的正确方法是什么?,spring,prepared-statement,jdbctemplate,spring-jdbc,Spring,Prepared Statement,Jdbctemplate,Spring Jdbc,根据我的理解,在Java中使用PreparedStatement是因为我们可以多次使用它。 但是我对使用SpringJDBC的PreparedStatementCreator有些困惑 例如考虑下面的代码, public class SpringTest { JdbcTemplate jdbcTemplate; PreparedStatementCreator preparedStatementCreator; ResultSetExtractor<String
例如考虑下面的代码,
public class SpringTest {
JdbcTemplate jdbcTemplate;
PreparedStatementCreator preparedStatementCreator;
ResultSetExtractor<String> resultSetExtractor;
public SpringTest() throws SQLException {
jdbcTemplate = new JdbcTemplate(OracleUtil.getDataSource());
preparedStatementCreator = new PreparedStatementCreator() {
String query = "select NAME from TABLE1 where ID=?";
public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
return connection.prepareStatement(query);
}
};
resultSetExtractor = new ResultSetExtractor<String>() {
public String extractData(ResultSet resultSet) throws SQLException,
DataAccessException {
if (resultSet.next()) {
return resultSet.getString(1);
}
return null;
}
};
}
public String getNameFromId(int id){
return jdbcTemplate.query(preparedStatementCreator, new Table1Setter(id), resultSetExtractor);
}
private static class Table1Setter implements PreparedStatementSetter{
private int id;
public Table1Setter(int id) {
this.id =id;
}
@Override
public void setValues(PreparedStatement preparedStatement) throws SQLException {
preparedStatement.setInt(1, id);
}
}
public static void main(String[] args) {
try {
SpringTest springTest = new SpringTest();
for(int i=0;i<10;i++){
System.out.println(springTest.getNameFromId(i));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
公共类SpringTest{
jdbc模板jdbc模板;
PreparedStatementCreator PreparedStatementCreator;
结果文本采集器结果文本采集器;
public SpringTest()引发SQLException{
jdbcTemplate=新的jdbcTemplate(OracleUtil.getDataSource());
preparedStatementCreator=新的preparedStatementCreator(){
String query=“从表1中选择名称,其中ID=?”;
公共PreparedStatement createPreparedStatement(连接)引发SQLException{
返回连接。准备声明(查询);
}
};
ResultsTextRactor=新的ResultsTextRactor(){
公共字符串extractData(ResultSet ResultSet)引发SQLException,
DataAccessException{
if(resultSet.next()){
返回resultSet.getString(1);
}
返回null;
}
};
}
公共字符串getNameFromId(int-id){
返回jdbcTemplate.query(preparedStatementCreator、new Table1Setter(id)、ResultsTextRactor);
}
私有静态类Table1Setter实现PreparedStatementSetter{
私有int-id;
公共表1服务器(int id){
this.id=id;
}
@凌驾
public void setValues(PreparedStatement PreparedStatement)引发SQLException{
编制的报表。setInt(1,id);
}
}
公共静态void main(字符串[]args){
试一试{
SpringTest SpringTest=新的SpringTest();
对于(int i=0;i
在调试并查看PreparedStatementCreator和JdbcTemplate内部发生的情况后,我知道PreparedStatementCreator每次都会创建新的PreparedStatement
我不知道为什么这会如此令人震惊,因为每次都是您自己的代码通过调用connection.prepareStatement(query);
来创建一个新的PreparedStatement
。如果您想重用同一个语句,那么就不应该创建一个新语句。您使用PreparedStatementCreator的方法是正确的
在每个新事务中,您都应该创建全新的PreparedStatement实例,这绝对正确。PreparedStatementCreator主要用于包装代码块,以便轻松创建PreparedStatement实例,而不是说您应该在每个itme重新创建新实例
PreparedStatement主要用于向DBMS发送模板化和预编译的SQL语句,这将为SQL执行节省一些预编译时间
总之,您所做的是正确的。使用PreparedStatement将比Statement性能更好。准备好的语句通常由底层连接池缓存,因此您不必担心是否每次都创建一个新语句
所以我认为你的实际用法是正确的
JdbcTemplate在执行语句后关闭该语句,因此如果您真的想重用同一条准备好的语句,可以代理该语句并在语句创建者中截取close方法
例如(未测试,仅作为示例):
我还尝试返回相同的PreparedStatement,然后得到错误“Closed Connection”,当我尝试使用相同的连接对象时,得到错误“Closed Statement”如果您在上面的示例中谈到,那可能是因为您正在进行正确的事务管理。在事务进行中,所有操作都将针对相同的连接执行,重用相同的语句应该不是问题。抱歉,上面的输入错误…请确认“您没有进行正确的事务管理”。
public abstract class ReusablePreparedStatementCreator implements PreparedStatementCreator {
private PreparedStatement statement;
public PreparedStatement createPreparedStatement(Connection conn) throws SQLException {
if (statement != null)
return statement;
PreparedStatement ps = doPreparedStatement(conn);
ProxyFactory pf = new ProxyFactory(ps);
MethodInterceptor closeMethodInterceptor = new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
return null; // don't close statement
}
};
NameMatchMethodPointcutAdvisor closeAdvisor = new NameMatchMethodPointcutAdvisor();
closeAdvisor.setMappedName("close");
closeAdvisor.setAdvice(closeMethodInterceptor);
pf.addAdvisor(closeAdvisor);
statement = (PreparedStatement) pf.getProxy();
return statement;
}
public abstract PreparedStatement doPreparedStatement(Connection conn) throws SQLException;
public void close() {
try {
PreparedStatement ps = (PreparedStatement) ((Advised) statement).getTargetSource().getTarget();
ps.close();
} catch (Exception e) {
// handle exception
}
}
}