[英]Right way to persist new object at runtime in Java EE?
簡介 (如果感到無聊,請跳過;)
嗨,大家好,我正在做一個我去年從“繼承”下來的學校項目。 這是一個用Java EE內置的Webapp,旨在對筆試訓練進行游戲化。 我的任務是在應用程序中包括一個新的漏洞(XXE)。現有的應用程序混合了CDI和EJB批注,盡管我尚未弄清原因。
我和我的小組中的任何人都沒有Java EE的經驗,盡管在過去的幾周中我盡了最大的努力來加快速度,但我對以下問題有些迷失,特別是在沒有“骯臟的駭客”的情況下解決了該問題。 ”將破壞MVC模式。
問題
我可以成功地將用戶上傳的.xml反序列化為“產品”的實例(或根據需要,在用戶上傳惡意數據時觸發漏洞利用)。
但是持久化對象不起作用,這似乎與我的UploadController類的范圍有關。 到目前為止,持久性僅在InitBean中完成,InitBean是一個單例,並在應用程序啟動后立即實例化。
啟動該應用程序后,原始作者的意圖不是允許將更多對象添加到數據庫中。
到目前為止,我嘗試了兩種方法:-在我的UploadController中模仿InitBean中PersistenceContext的用法(請參見下面的代碼)。 這將導致javax.persistence.TransactionRequiredException。 我對錯誤進行了一些閱讀,我猜我的控制器的生命周期錯誤,但是我不太明白。
我還嘗試將持久性功能包裝在InitBean中,並將其作為靜態方法公開(感覺非常丑陋,也行不通)。
題
因此,最終,我的問題是:在應用程序啟動后,向數據庫添加項目的正確方法是什么? 如果是這樣,我是否應該從我的控制器類中執行此操作,那么如何獲得正確的作用域/事務? 還是我應該完全走另一條路? 解釋非常感謝。
模型:
@Entity
@XmlRootElement
@Table(name = "product")
public class Product implements Serializable, Comparable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true, nullable = false)
private String name;
@Column(nullable = false)
private float price;
@Column(length = 512) // hibernate default of 255 not sufficient for our flags
private String description;
@Column(name = "img_path")
private String imagePath;
@ManyToOne
@JoinColumn(name = "category_fk")
private Category category;
@OneToMany(mappedBy = "product", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Recension> recensions;
@Column
private boolean active;
public Product() {
}
public Product(String name, float price, String description, String imgPath, Category category) {
this.name = name;
this.price = price;
this.description = description;
this.imagePath = imgPath;
this.category = category;
this.active = true;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getImagePath() {
return imagePath;
}
public void setImagePath(String imagePath) {
this.imagePath = imagePath;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
public Set<Recension> getRecensions() {
return recensions;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
@Override
public int compareTo(Object o) {
return Long.compare(((Product) o).getId(), this.id);
}
// Convenience methods
public int ratingCount() {
return recensions.size();
}
public float averageRating() {
// avoid division by 0
if (ratingCount() == 0) {
return 0;
}
int sum = 0;
for (Recension r : recensions) {
sum += r.getRating();
}
return sum/ratingCount();
}
}
ModelDAO:
package at.technikum.mic16.prj.dao;
import at.technikum.mic16.prj.entity.Category;
import at.technikum.mic16.prj.entity.Product;
import java.io.Serializable;
import java.util.List;
import javax.enterprise.inject.Model;
import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.apache.commons.lang3.StringEscapeUtils;
/**
*
* @author leandros
*/
@Model
public class ProductDAO implements Serializable {
@PersistenceContext(unitName = "daisy-persunit")
private EntityManager em;
public Product findByID(Long id) {
return em.find(Product.class, id);
}
/**
* Find all products, optionally paginated
* @param offset Offset to result set
* @param count Number of rows to return, a value <= 0 will result in pagination being disabled
* @return
*/
public List<Product> findAll(int offset, int count) {
Query q = em.createQuery("FROM Product p WHERE active is true", Product.class);
if (count > 0) {
q.setFirstResult(offset);
q.setMaxResults(count);
}
return q.getResultList();
}
/**
* Find all products matching substring in name or description
* @param substring Substring to match
* @param offset Offset to result set
* @param count Number of rows to return, a value <= 0 will result in pagination being disabled
* @return
*/
public List<Product> findByNameOrDescription(String substring, int offset, int count) {
Query q = em.createQuery("FROM Product p WHERE (name like :substring or description like :substring) AND active is true", Product.class);
q.setParameter("substring", "%" + substring + "%");
if (count > 0) {
q.setFirstResult(offset);
q.setMaxResults(count);
}
return q.getResultList();
}
/**
* Find all products - this is vulnerable to SQL injection and also unescapes input by purpose
* Result is also sorted independently of SQL (no order by) in order to display record with reward first (highest id, see comparator)
* @param queryString
* @return
*/
public List<Product> findByExactName(String queryString) {
String unescaped = StringEscapeUtils.unescapeHtml4(queryString);
Query q = em.createQuery("FROM Product p WHERE active is true AND name = '" + unescaped + "'", Product.class);
List result = q.getResultList();
result.sort(null);
return result;
}
/**
* Find all products matching specific category
* @param category Category to match
* @param offset Offset to result set
* @param count Number of rows to return, a value <= 0 will result in pagination being disabled
* @return
*/
public List<Product> findByCategory(Category category, int offset, int count) {
Query q = em.createQuery("FROM Product p WHERE category_fk = :category AND active is true", Product.class);
q.setParameter("category", category);
if (count > 0) {
q.setFirstResult(offset);
q.setMaxResults(count);
}
return q.getResultList();
}
/**
* Find inactive products
* @return List of inactive products
*/
public List<Product> findInactive() {
Query q = em.createQuery("FROM Product p WHERE active is false", Product.class);
return q.getResultList();
}
public void persist(Product...products) {
for (Product product : products) {
em.persist(product);
}
}
public void merge(Product product) {
em.merge(product);
}
public void delete(Product product) throws EntityNotFoundException {
// attach and delete it...
Product attached = em.find(Product.class, product.getId());
if (attached != null) {
em.remove(attached);
} else {
throw new EntityNotFoundException("Product not found with id: " + product.getId());
}
}
}
初始化豆
@Singleton
@LocalBean
@Startup
public class InitBean {
// file path of JS to by executed by phantom JS
private static final String XSS_FILE_PATH = "/home/daisy/.config";
// this file is intended for holding a token receivable by exploiting the command execution in admin interface
public static final String HIDDEN_FILE_PATH_CE = "/tmp/TOKEN_REWARD.TXT";
// this file is intended for holding a token receivable by exploiting the xxe vulnerability in the upload section
public static final String HIDDEN_FILE_PATH_XXE = "/tmp/hidden/TOKEN_REWARD2.TXT";
// this user bears a special description -> reward token
private static final String USER_WITH_TOKEN = "user2@foo.at";
//Admin User Testing
private static final String ADMIN_USER = "admin@foo.at";
@Inject
private WebshopService webshopService;
@Inject
private CategoryDAO categoryDAO;
@Inject
private ProductDAO productDAO;
@Inject
private OrderItemDAO orderItemDAO;
@Inject
private PlacedOrderDAO placedOrderDAO;
@Inject
private RecensionDAO recensionDAO;
@Inject
private UserDAO userDAO;
@Inject
private UserRoleDAO userRoleDAO;
private String installationToken;
private Map<Vulnerability, String> rewardTokens;
public void setInstallationToken(String installationToken) {
this.installationToken = installationToken;
}
public Map<Vulnerability, String> getRewardTokens() {
return rewardTokens;
}
public void setRewardTokens(Map<Vulnerability, String> rewardTokens) {
this.rewardTokens = rewardTokens;
}
@PostConstruct
public void init() {
try {
insertSampleData();
installationToken = webshopService.retrieveInstallationToken();
/* if there is no token, retrieving it would fail with FileNotFoundException
so just go on inserting vulnerability data...
*/
generateRewardTokens();
insertVulnerabilityData();
} catch (NoSuchAlgorithmException | UnsupportedEncodingException ex) {
Logger.getLogger(InitBean.class.getName()).log(Level.SEVERE, null, ex);
} catch (FileNotFoundException ignore) {
// retrieving installation token failed
} catch (IOException ex) {
Logger.getLogger(InitBean.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* Inserts sample data into the database
* @throws NoSuchAlgorithmException
* @throws UnsupportedEncodingException
*/
private void insertSampleData() throws NoSuchAlgorithmException, UnsupportedEncodingException {
UserRole user1Role = new UserRole("han", UserRole.Role.CUSTOMER);
UserRole user2Role = new UserRole(USER_WITH_TOKEN, UserRole.Role.CUSTOMER);
UserRole user3Role = new UserRole(ADMIN_USER, UserRole.Role.ADMIN);
userRoleDAO.persist(user1Role, user2Role, user3Role);
User user1 = new User("user1@foo.at", JBossPasswordUtil.getPasswordHash("user1"), "User", "1");
User user2 = new User(USER_WITH_TOKEN, JBossPasswordUtil.getPasswordHash(RandomStringUtils.randomAlphanumeric(12)), "User", "2");
User user3 = new User(ADMIN_USER, JBossPasswordUtil.getPasswordHash("admin"), "Iam", "God");
userDAO.persist(user1, user2, user3);
Category clothes = new Category("Clothes");
categoryDAO.persist(clothes);
Category men = new Category("Men");
men.setParent(clothes);
categoryDAO.persist(men);
Category trousersMen = new Category("Trousers");
trousersMen.setParent(men);
categoryDAO.persist(trousersMen);
Category electro = new Category("Electro");
categoryDAO.persist(electro);
Category telly = new Category("Television");
telly.setParent(electro);
categoryDAO.persist(telly);
Category hoover = new Category("Hoover");
hoover.setParent(electro);
categoryDAO.persist(hoover);
Category smartphone = new Category("Smartphone");
smartphone.setParent(electro);
categoryDAO.persist(smartphone);
Product phillips1 = new Product("Philips 55PUK4900", 679.99f, "This new Phillips is superb...", "images/products/Phillips_55PUK4900.jpg", telly);
Product phillips2 = new Product("Phillips 55PUS6031", 998.99f, "The brand new Phillips...", "images/products/Phillips_55PUS6031.jpg", telly);
Product phillips3 = new Product("Phillips 50PFK4109", 328.99f, "This new Phillips is not as good...", "images/products/Phillips_50PFK4109.jpg", telly);
Product samsung1 = new Product("Samsung UE55JU6470", 850.00f, "This new Samsung is superb...", "images/products/Samsung_UE55JU6470.jpg", telly);
Product samsung2 = new Product("Samsung UE55K5660", 1100.00f, "This new Samsung is not as good...", "images/products/Samsung_UE55K5650.jpg", telly);
Product samsung3 = new Product("Samsung UE65JU6070", 1200.99f, "This new Samsung is not as good...", "images/products/Samsung_UE65JU6070.jpg", telly);
Product panasonic1 = new Product("Panasonic TX-49DXW654", 679.99f, "This new Phillips is superb...", "images/products/Panasonic_TX49DXW654.jpg", telly);
Product panasonic2 = new Product("Panasonic TX65AXW904", 998.99f, "This new Phillips is not as good...", "images/products/Panasonic_TX65AXW904.jpg", telly);
Product panasonic3 = new Product("Panasonic TX55CXW684", 328.99f, "This new Phillips is not as good...", "images/products/Panasonic_TX55CXW684.jpg", telly);
Product hoover1 = new Product("iRobot Roomba 980", 750.90f, "Brand new and strong...", "images/products/Irobot_Roomba980.jpg", hoover);
Product hoover2 = new Product("iRobot Roomba 886", 930.90f, "Brand new and strong...", "images/products/Irobot_Roomba886.jpg", hoover);
Product hoover3 = new Product("iRobot Roomba 875", 487.90f, "Brand new and strong...", "images/products/IrobotRoomba875.jpg", hoover);
Product hoover4 = new Product("Dyson Big Ball Parquet", 640.90f, "Brand new and strong...", "images/products/Dyson_Bigball1.jpg", hoover);
Product hoover5 = new Product("Dyson DC37c Parquet", 321.90f, "Brand new and strong...", "images/products/Dyson_Dc37.jpg", hoover);
Product hoover6 = new Product("Dyson DC37 Musclehead", 219.90f, "Brand new and strong...", "images/products/Dyson_Dc37misclehead.jpg", hoover);
Product smartphone1 = new Product("Apple Iphone 7", 860.90f, "Brand new and strong...", "images/products/Iphone7.jpg", smartphone);
Product smartphone2 = new Product("Apple Iphone SE", 450.90f, "Brand new and strong...", "images/products/Iphone_SE.jpg", smartphone);
Product smartphone3 = new Product("Samsung Galaxy S8", 750.90f, "Brand new and strong...", "images/products/Samsung_S8.jpg", smartphone);
Product smartphone4 = new Product("Samsung Galaxy S6", 650.90f, "Brand new and strong...", "images/products/Samsung_S6.jpg", smartphone);
Product smartphone5 = new Product("Google Pixel", 800.90f, "Brand new and strong...", "images/products/Google_Pixel.jpg", smartphone);
Product smartphone6 = new Product("Huawei P10", 700.90f, "Brand new and strong...", "images/products/Huawei_P10.jpg", smartphone);
Product jeans1 = new Product("Lewis", 110.90f, "Brand new and strong...", "images/products/jeans1.jpg", trousersMen);
Product jeans2 = new Product("G-Star P10", 120.90f, "Brand new and strong...", "images/products/jeans2.jpg", trousersMen);
Product jeans3 = new Product("Review P10", 60.90f, "Brand new and strong...", "images/products/jeans3.jpg", trousersMen);
Product jeans4 = new Product("Replay", 75.90f, "Brand new and strong...", "images/products/jeans4.jpg", trousersMen);
Product jeans5 = new Product("Diesel", 160.90f, "Brand new and strong...", "images/products/jeans5.jpg", trousersMen);
Product jeans6 = new Product("Mustang", 55.90f, "Brand new and strong...", "images/products/jeans6.jpg", trousersMen);
productDAO.persist(phillips1, phillips2, phillips3, samsung1, samsung2, samsung3, panasonic1, panasonic2, panasonic3, hoover1, hoover2, hoover3, hoover4, hoover5, hoover6,
smartphone1, smartphone2, smartphone3, smartphone4, smartphone5, smartphone6, jeans1, jeans2, jeans3, jeans4, jeans5, jeans6);
Recension recension1 = new Recension();
recension1.setCreationDate(LocalDateTime.now().minusDays(14));
recension1.setProduct(phillips1);
recension1.setRating(4);
recension1.setUser(user1);
recension1.setText("I like it");
Recension recension2 = new Recension();
recension2.setCreationDate(LocalDateTime.now().minusDays(3).minusSeconds((int) (Math.random()*1337)));
recension2.setProduct(phillips1);
recension2.setRating(3);
recension2.setUser(user2);
recension2.setText("It's ok, don't expect too much.");
recensionDAO.persist(recension1, recension2);
}
/**
* Generates all the reward tokens in rewardTokens
*/
private void generateRewardTokens() {
rewardTokens = new HashMap<>();
for (Vulnerability v : Vulnerability.values()) {
try {
rewardTokens.put(v, DaisyPointsCrypter.encryptMessage(installationToken, "Vulnerability|" + v.name()));
//Logger.getLogger(InitBean.class.getName()).log(Level.INFO, "Generated token: ".concat(rewardTokens.get(v)));
} catch (DaisyPointsEncryptionException ex) {
rewardTokens = null;
Logger.getLogger(InitBean.class.getName()).log(Level.SEVERE, "Error generating reward tokens", ex);
}
}
}
/**
* Puts reward tokens to their respective places
* @throws IOException
*/
public void insertVulnerabilityData() throws IOException {
/*
this should only happen upon invocation via TokenController and not
on subsequent restarts, when token is already known
*/
if (rewardTokens == null) {
generateRewardTokens();
}
// hidden product - find via SQL injection
Category hoover = categoryDAO.findByName("Hoover");
Product prod1 = new Product("SQL Injection exploited!", 666, "Congratulations, here is your token for the points system:\n".concat(rewardTokens.get(Vulnerability.SQLI_PRODUCTS)), "images/thumbs_up.png", hoover);
prod1.setActive(false);
productDAO.persist(prod1);
// hidden user - find via indirect object reference
User user2 = userDAO.findById(USER_WITH_TOKEN);
user2.setDescription(rewardTokens.get(Vulnerability.INSECURE_DIRECT_OBJECT_REFERENCE));
// hidden file - find via hidden directory and CommandService
File f = new File(HIDDEN_FILE_PATH_CE);
BufferedWriter bw = null;
try {
bw = new BufferedWriter(new FileWriter(f));
bw.write("Command execution exploited, here is your token for the points system:");
bw.newLine();
bw.write(rewardTokens.get(Vulnerability.HIDDEN_FILE));
bw.newLine();
bw.flush();
} finally {
FileUtil.safeClose(bw);
}
// hidden file - find via hidden directory and CommandService
writeFile(HIDDEN_FILE_PATH_CE, Vulnerability.HIDDEN_FILE);
// hidden file - find via hidden directory and CommandService
writeFile(HIDDEN_FILE_PATH_XXE, Vulnerability.XXE_UPLOAD);
// prepare phantom JS script
f = new File(XSS_FILE_PATH);
bw = null;
try {
bw = new BufferedWriter(new FileWriter(f));
bw.write(preparePhantomJSScript());
bw.flush();
} finally {
FileUtil.safeClose(bw);
}
}
private void writeFile(String pathname, Vulnerability vulnerability) throws IOException {
File f;
BufferedWriter bw;
f = new File(pathname);
bw = null;
try {
bw = new BufferedWriter(new FileWriter(f));
bw.write("Command execution exploited, here is your token for the points system:");
bw.newLine();
bw.write(rewardTokens.get(vulnerability));
bw.newLine();
bw.flush();
} finally {
FileUtil.safeClose(bw);
}
}
/**
* Delete any structures (DB reows, files) containing reward tokens
*/
public void deleteVulnerabilityData() {
for (Product p : productDAO.findInactive()) {
productDAO.delete(p);
}
User user2 = userDAO.findById(USER_WITH_TOKEN);
user2.setDescription("");
File f = new File(HIDDEN_FILE_PATH_CE);
f.delete();
f = new File(XSS_FILE_PATH);
f.delete();
}
/**
Writes token in script invoked by phantom JS
* @param token
* @return
* @throws UnsupportedEncodingException
* @throws DaisyPointsEncryptionException
*/
private String preparePhantomJSScript() throws UnsupportedEncodingException {
// this holds the phantom JS script to be executed in portable fashion
String base64 = "dmFyIHBhZ2UgPSByZXF1aXJlKCd3ZWJwYWdlJykuY3JlYXRlKCk7CgpwYWdlLnNldHRpbmdzLnVzZXJBZ2VudCA9ICdUT0tFTic7CnBhZ2Uudmlld3BvcnRTaXplID0geyB3aWR0aDogMTkyMCwgaGVpZ2h0OiAxMDgwIH07CgpwYWdlLm9wZW4oJ2h0dHA6Ly8xMjcuMC4wLjE6ODA4MC9kYWlzeS13ZWIvJywgZnVuY3Rpb24oKSB7CgogICAgICAgIHBhZ2UuZXZhbHVhdGUoZnVuY3Rpb24oKSB7CiAgICAgICAgICAgICAgICBQcmltZUZhY2VzLmFiKHtzOmRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ1thbHQ9InByb2R1Y3QtMSJdJykuZ2V0QXR0cmlidXRlKCJpZCIpfSk7CiAgICAgICAgfSk7CgogICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7CiAgICAgICAgICAgICAgICBwYWdlLmV2YWx1YXRlKGZ1bmN0aW9uKCkge30pOwogICAgICAgIH0sIDIwMDApOwoKICAgICAgICBjb25zb2xlLmxvZygiZmluaXNoIik7CgogICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7CiAgICAgICAgICAgICAgICAvL3BhZ2UucmVuZGVyKCd0ZXN0LnBuZycpOwogICAgICAgICAgICAgICAgcGhhbnRvbS5leGl0KCk7CiAgICAgICAgfSwgMjAwMCk7Cn0pOwo=";
String script = new String(Base64.decodeBase64(base64), "UTF-8");
// modify user agent to use appropriate reward token string
return script.replace("TOKEN", rewardTokens.get(Vulnerability.XSS_REMOTE_SCRIPT));
}
//Awful Hack:
// public void persistProduct(Product product){
// productDAO.persist(product);
// }
}
UploadController
package at.technikum.mic16.prj.controller;
/**
* Created by Dave on 11/05/2018.
*/
@ManagedBean(name = "uploadController")
@ApplicationScoped
@Startup
@Singleton
//@Stateful
public class UploadController implements Serializable {
private Part file;
private String xmlString;
@Inject
private ProductDAO productDAO;
public void doOutput(Product product) {
if (product == null) return;
JAXBContext jc;
{
try {
PrintStream ps = new PrintStream(new StringOutputStream(), true);
// PrintStream ps = new PrintStream(new File("product.xml"));
System.setOut(ps);
jc = JAXBContext.newInstance(Product.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(product, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
public void upload() {
try {
setXmlString(new Scanner(file.getInputStream())
.useDelimiter("\\A").next());
Product product = deserializeProduct(getXmlString());
productDAO.persist(product);
doOutput(product);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public Part getFile() {
return file;
}
public void setFile(Part file) {
this.file = file;
}
public String getXmlString() {
return xmlString;
}
public void setXmlString(String pXmlString) {
xmlString = pXmlString;
}
//Parsing xml back to object (+vuln) -> should eventally go into another class
public Product deserializeProduct(String xmlString) {
try {
JAXBContext jc = JAXBContext.newInstance(Product.class);
XMLInputFactory xmlInputFactory = XMLInputFactory.newFactory();
xmlInputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, true);
xmlInputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, true);
XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(new StringReader(xmlString));
Unmarshaller unmarshaller = jc.createUnmarshaller();
return (Product) unmarshaller.unmarshal(xmlStreamReader);
} catch (JAXBException pE) {
pE.printStackTrace();
return null;
} catch (XMLStreamException pE) {
pE.printStackTrace();
return null;
}
}
}
感謝您的任何幫助!
以前,我使用@Singleton + @Startup就像執行此操作一樣。
但是這種方法存在一些問題。
現在我使用這種方法:
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version="2.1">
<persistence-unit name="db-connection" transaction-type="JTA">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>JTA-Connection</jta-data-source>
<non-jta-data-source>None-JTA-Connection</non-jta-data-source>
<properties>
<property name="tomee.jpa.cdi" value="false"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle12cDialect"/>
<!--<property name="hibernate.current_session_context_class" value="thread"/>-->
<property name="hibernate.event.merge.entity_copy_observer" value="allow"/>
<property name="hibernate.enable_lazy_load_no_trans" value="true"/>
<!--<property name="hibernate.show_sql" value="true"/>-->
<!--<property name="hibernate.format_sql" value="true"/>-->
<!--<property name="hibernate.hbm2ddl.auto" value="create-drop"/>-->
<!--<property name="hibernate.hbm2ddl.auto" value="create"/>-->
<!--<property name="hibernate.hbm2ddl.auto" value="update"/>-->
<property name="hibernate.hbm2ddl.import_files_sql_extractor"
value="org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor"/>
<property name="hibernate.hbm2ddl.import_files" value="initialize-database.sql"/>
</properties>
</persistence-unit>
</persistence>
注意:persistence.xml中的hibernate.hbm2ddl.import_files。
其實太方便了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.