调用connection.rollback()会抛出NullPointerException

时间:2012-10-25 16:16:12

标签: java mysql nullpointerexception

运行项目会抛出此错误:

java.lang.NullPointerException
    com.myproject.crud.EmployeesJDBCImpl.withDB(EmployeesJDBCImpl.java:157)
    com.myproject.crud.EmployeesJDBCImpl.doList(EmployeesJDBCImpl.java:119)
    com.myproject.crud.EmployeesJDBCImpl.listEmployees(EmployeesJDBCImpl.java:111)
    com.myproject.crud.EmployeesJDBCImpl$Proxy$_$$_WeldClientProxy.listEmployees(EmployeesJDBCImpl$Proxy$_$$_WeldClientProxy.java)
    com.myproject.crud.EmployeesListServlet.doGet(EmployeesListServlet.java:36)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:722)

try块失败并跳转到catch块,connection对象在调用connection.rollback()时似乎为空。很难理解为什么会发生这种情况。 context.xml中提供的用户名和密码是正确的。

EmployeesJDBCImpl.java

package com.myproject.crud;

import java.util.ArrayList;
import java.util.List;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.enterprise.context.ApplicationScoped;
import javax.annotation.Resource;
import javax.sql.DataSource;

@ApplicationScoped @JDBC
public class EmployeesJDBCImpl implements EmployeesRepository {

    @Resource(name="jdbc/EmployeesDB")
    private DataSource dS;

    @Override
    public Employee viewEmployee(final String id) {
        return withDB(new JDBCRunner<Employee>(){
            @Override
            public Employee run(Connection connection) throws Exception{
                PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM employees WHERE id = ?");

                preparedStatement.setString(1, id);

                ResultSet rs = preparedStatement.executeQuery();
                if(rs.next()){
                    Employee employee = new Employee();
                    employee.setId(rs.getString("id"));
                    employee.setName(rs.getString("name"));
                    employee.setPhone(rs.getString("phone"));
                    employee.setEmail(rs.getString("email"));                   
                    return employee;
                }else{
                    return null;
                }
        }});
    }

    private <T> T withDB(JDBCRunner<T> runner){
        Connection connection = null;

        try{
            connection = dS.getConnection();
            boolean auto = connection.getAutoCommit();
            connection.setAutoCommit(false);
            T result = runner.run(connection);
            connection.commit();
            connection.setAutoCommit(auto);
            return result;
        }catch(Exception e){
            try{
                connection.rollback(); // Nullpointer exception here
            }catch(SQLException ex){
            }
            //throw new EmployeesException(e);
        }finally{
            if(connection != null){
                try{
                    connection.close();
                }catch(Exception ex){
                }
            }
        }
        return null;
    }
}

META-INF / context.xml中

<?xml version="1.0" encoding="UTF-8"?>
<Context>
    <Resource name="jdbc/EmployeesDB" auth="Container" type="javax.sql.DataSource"
               maxActive="100" maxIdle="30" maxWait="10000"
               username="root" password="secret" driverClassName="com.mysql.jdbc.Driver"
               url="jdbc:mysql://localhost:3306/javatest"/>
</Context>

WEB-INF / web.xml中

...
    <description>MySQL Employees App</description>
    <resource-ref>
      <description>db connection</description>
      <res-ref-name>jdbc/EmployeesDB</res-ref-name>
      <res-type>javax.sql.DataSource</res-type>
      <res-auth>Container</res-auth>
    </resource-ref>
...

4 个答案:

答案 0 :(得分:1)

可能是因为您的连接未正确创建。在执行回滚之前,您应该检查connection是否为空。

此外,您应该至少记录错误,这样您就可以了解正在发生的事情。

我怀疑你的dS对象为空,可能由于名称不匹配而没有正确注入。

答案 1 :(得分:1)

尝试从try块中记录异常。

最有可能的是,这一行会抛出异常:  connection = dS.getConnection();

一般情况下,如果可能,应避免捕获所有异常。并记录异常,以便您知道发生了什么。因为例外,如名称所示,不需要。

- TB

答案 2 :(得分:1)

我无法看到您初始化DataSource的位置

 connection = dS.getConnection();

你必须有一些dS的查找代码

类似于:

Context ctx=new InitialContext();                        
DataSource dS=(DataSource)ctx.lookup("jdbc/sampledb");   
Connection con=dS.getConnection(); 

答案 3 :(得分:1)

有两个可能的原因:

  • dS.getConnection()正在抛出异常。可以是任何异常,因为你的catch块会捕获所有内容。您在 catch块中获得NullPointerException ,因为connection在回滚时为null
  • dS.getConnection()返回null,导致connection.getAutoCommit()抛出NullPointerException。这是因为connection已通过null设置为dS.getConnection()

在你的catch区块中,从e.printStackTrace()开始,找出真正的问题:

    ...
    }catch(Exception e){
        e.printStackTrace(); //This should show you what the real problem is
        try{
            connection.rollback();
        }catch(SQLException ex){
        }
        //throw new EmployeesException(e);
    }finally{
    ...

<强>解决方案:

  • 在catch块中,在进行回滚之前检查connection是否不是null。如果从未创建数据库连接,则不必回滚它。 我每天都会在大型项目中处理这种设置,这就是我们的工作。
  • 不太理想的解决方案:完成dS.getConnection()后,如果connection不是null,请继续 。您可以根据需要使用if (connection != null) { /* rest of code */ }if (connection == null) throw new NullPointerException();