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;
}
...
}
不过我有两个问题:
我不想直接使用 JDBC - 有没有办法做到这一点 'pure JPA'(编辑:不是 EJB)?
如果我必须这样做,PreparedStatement 是否包含在容器管理的事务中?
另一个编辑:上面的代码完成了工作——我现在已经测试过了。但我认为它并不漂亮。
我认为您将 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 ...;
}
...
}
我正在开发 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;
}
...
}
不过我有两个问题:
我不想直接使用 JDBC - 有没有办法做到这一点 'pure JPA'(编辑:不是 EJB)?
如果我必须这样做,PreparedStatement 是否包含在容器管理的事务中?
另一个编辑:上面的代码完成了工作——我现在已经测试过了。但我认为它并不漂亮。
我认为您将 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 ...;
}
...
}