EJB 和 preparedStatement?

EJB and preparedStatement?

我正在开发 Web 应用程序,除其他外,我需要将文件上传到 mysql table 中的 BLOB 列。据我所知,这可以通过 JDBC 调用(PrepareStatement() 等)来完成,但我希望能够在 EJB class 中做到这一点——我拼凑起来的看起来像这样:

@Stateless
public class ItemsSession {
    @PersistenceContext(unitName ="officePU")
    private EntityManager em;
    private List<Items> itl;
    private static final Logger logger=
            Logger.getLogger(ItemsSession.class.getName());
...
    public String updateDocument(Integer id,InputStream is) throws SQLException{
        String msg="";
        try{
            java.sql.Connection conn = em.unwrap(java.sql.Connection.class);
            PreparedStatement pstmt=conn.prepareStatement("UPDATE Documents SET doc = ? WHERE id = ?");
            pstmt.setBinaryStream(1, is);
            pstmt.setLong(2, id);
            pstmt.executeUpdate();
            pstmt.close();
        }
        catch (PersistenceException e){
            msg=e.getMessage();
        }

        return msg;
    }
...
}

不过我有两个问题:


另一个编辑:上面的代码完成了工作——我现在已经测试过了。但我认为它并不漂亮。

我认为您将 EJB 与 JPA 结合使用,因为您使用的是:

@PersistenceContext(unitName ="officePU")

参考:http://www.adam-bien.com/roller/abien/entry/ejb_3_persistence_jpa_for

要以 JPA 方式保留 BLOB 值,您必须做的第一件事是定义一个实体。下面是一个伪代码示例:

@Entity
public class Documents {
    @Id
    private Long id;

    @Lob
    private byte[] doc;

    // .... getters + setters 
}

然后你修改你的EJB如下:

@Stateless
public class ItemsSession {
    @PersistenceContext(unitName ="officePU")
    private EntityManager em;
    // ... the rest of your code

    public String updateDocument(Integer id,InputStream is) throws SQLException{
        String msg = "";
        Documents docs = em.find(Documents.class, id); // fetch record from DB
        // Assuming your InputStream is a ByteArrayInputStream
        byte[] doc = new byte[is.available()]; // create target array
        is.read(doc, 0, doc.length);  // read bytes into byte array
        docs.setDoc(doc); // 

        return msg; // returning exception message from method call?????
    }
    ...
}

如果不更改默认值,默认情况下会在事务中调用 EJB 方法。所以当你的方法退出时,更新应该与数据库同步。

如果您阅读并理解了 JPA 的基础知识,这个答案只会对您有所帮助。 here 是 JPA 持久性的官方教程,以及网络上的其他许多教程。

更新

I would like not to use JDBC directly - is there a way to do this that is 'pure JPA'

没有

If I have to do it this way, is the PreparedStatement included in the container managed transaction?

没有。但是你可以使用 bean 管理的事务。如果您想使用 BMT,以下伪代码可能对您有所帮助:

@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class ItemsSession {

    @Resource UserTransaction ut;
    @Resource DataSource datasource;  // you should define datasource on your application server

    ...
    public String updateDocument(Integer id,InputStream is) throws SQLException{
        // ...
        try (java.sql.Connection conn = datasource.getConnection();
            PreparedStatement pstmt=conn.prepareStatement("UPDATE Documents SET doc = ? WHERE id = ?")) {

            pstmt.setBinaryStream(1, is);
            pstmt.setLong(2, id);

            ut.begin();
            pstmt.executeUpdate();
            ut.commit();

        } catch (PersistenceException e){
            // ... error handling
        }

        return ...;
    }
...
}