mysql - JPA 实体未保存在数据库中

标签 mysql hibernate jpa jakarta-ee wildfly

我有一个使用 JPA 和 MySQL 在 WildFly 10.1.0 上运行的 JEE 应用程序。

我有一个无状态服务,代表一个网络爬虫,它从给定的网站中提取内容,创建结构化的 POJO 实体并将这些实体保存在数据库中。我的问题是虽然没有抛出异常,但 JPA 实体没有保存在数据库中。 我的无状态网络爬虫:

@Stateless
public class ImmoweltBot {

    public static final String URL = "https://www.immowelt.at/";
    public static final String queryURL = URL + "/liste/wien/wohnungen/mieten?sort=relevanz";


    @Inject
    private HomeToDealDBService homeToDealDBService;


    @PostConstruct
    public void initialize() {
        System.setProperty("webdriver.chrome.driver", "C:\\Temp\\chromedriver.exe");
    }


    public void crawl () throws Exception {

        String URLPage = StringUtils.EMPTY;
        int page = 1;
        int totalNumberOfEntities = 6000;
        int numberOfEntitiesFound = 0;

        List<WebElement> elemnts = new ArrayList<>();

        WebDriver webDriver = new ChromeDriver();

        outer:
        while (numberOfEntitiesFound < totalNumberOfEntities){

        webDriver.get(queryURL + URLPage);      


        final int totalNumberOfKeyDowns = 190;
        int keyDownTries = 0;
        while ((++keyDownTries < totalNumberOfKeyDowns)) {
            webDriver.findElement(By.tagName("body")).sendKeys(Keys.DOWN);

        }
        elemnts = webDriver.findElements(By.xpath("//*[contains(@class, 'clear relative js-listitem')]"));

        WebElement elem = webDriver.findElement(By.xpath("//*[contains(@class, 'ellipsis margin_none')]"));
        totalNumberOfEntities = Utils.parseNumber(elem.getText()).intValue();

        for (int i = 0; i < elemnts.size(); i++) {
            WebElement divListItemClear = elemnts.get(i);
            HomeToDeal homeToRent = new HomeToDeal();
            String exposeURL = divListItemClear.findElement(By.tagName("a")).getAttribute("href");
            homeToRent.setURL(exposeURL);

            try {
                homeToDealDBService.saveEntity(homeToRent);
                Logger.getLogger(ImmoweltBot.class).info("Entity " +  homeToRent + " saved");
            }
            catch (EntityExistsException eex){
                Logger.getLogger(ImmoweltBot.class).warn("Entity already saved " + homeToRent.getURL());
                break outer;
            }
        }
        URLPage = "&cp="+ (++page);
        numberOfEntitiesFound+=elemnts.size();
     }
    }
}

我的 HomeToDealDBService 类:

@Stateless
public class HomeToDealDBService {

    @PersistenceContext
    private EntityManager em;


    @TransactionAttribute(TransactionAttributeType.REQUIRED) 
    public void saveEntity(HomeToDeal homeToDeal) throws EntityExistsException{
        this.em.persist(homeToDeal);
    }

}

我的 POJO 类:

@Entity
@Table(name = "home")
@Access(AccessType.FIELD)
public class HomeToDeal implements Comparable<HomeToDeal>, Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    @Column(name = "id", updatable=false, nullable=false)
    private int id;
    private String URL;
    private String mainImage;
    private String imageFolderPath;
    private String description;
    private byte noRooms;
    private BigDecimal nutzflaeche; // area in sqm
    private BigDecimal wohnflaeche;

触发爬虫的 servlet:

@WebServlet("/test")
public class TestServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    @Inject
    private ImmoweltBot immoweltBot;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException {
        try {
            immoweltBot.crawl();
        } catch (Exception e) {
            throw new ServletException(e);
        }
    }

}

我的 persistence.xml:

<?xml version="1.0" encoding="UTF-8" ?>
    <persistence xmlns="http://java.sun.com/xml/ns/persistence"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
     http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">

       <persistence-unit name="IamOK" transaction-type="JTA">
         <description>Home to Deal</description>
         <provider>org.hibernate.ejb.HibernatePersistence</provider>

         <jta-data-source>java:/MySqlDS_HomeToDeal</jta-data-source> 
         <properties>
                <property name="hibernate.dialect" value = "org.hibernate.dialect.MySQLDialect" />
                <property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/>  
                <property name="hibernate.show_sql" value="true"></property>  
                <property name="hibernate.max_fetch_depth" value="3" />
                <property name="hibernate.hbm2ddl.auto" value="create"/> 
                <property name="hibernate.show_sql" value="true" />
            </properties>
       </persistence-unit>

    </persistence>

我在 WildFly standalone.xml 中的数据源:

    <datasource jta="true" jndi-name="java:/MySqlDS_HomeToDeal" pool-name="MySqlDS_HomeToDeal" enabled="true" use-java-context="true" use-ccm="true">
                <connection-url>jdbc:mysql://localhost:3306/homeToDeal?autoReconnect=true</connection-url>
                <driver>mysql</driver>
                <transaction-isolation>TRANSACTION_READ_COMMITTED</transaction-isolation>
                <pool>
                    <min-pool-size>10</min-pool-size>
                    <max-pool-size>100</max-pool-size>
                    <prefill>true</prefill>
                </pool>
                <security>
                    <user-name>homeToDealuser</user-name>
                    <password>homeToDeal123</password>
                </security>
                <validation>
                    <check-valid-connection-sql>SELECT 1</check-valid-connection-sql>
                </validation>
                <timeout>
                    <idle-timeout-minutes>0</idle-timeout-minutes>
                    <query-timeout>600</query-timeout>
                </timeout>
                <statement>
                    <prepared-statement-cache-size>100</prepared-statement-cache-size>
                    <share-prepared-statements>true</share-prepared-statements>
                </statement>
            </datasource>

数据库中的结果:

select * from home;

enter image description here

我的 pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>seller</groupId>
    <artifactId>home.digest</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>home.digest Maven Webapp</name>
    <!-- FIXME change it to the project's website -->
    <url>http://maven.apache.org</url>
    <repositories>
        <repository>
            <id>prime-repo</id>
            <name>Prime Repo</name>
            <url>http://repository.primefaces.org</url>
        </repository>
    </repositories>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>3.141.59</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpcore -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore</artifactId>
            <version>4.4.10</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.6</version>
        </dependency>
        <dependency>
            <groupId>org.primefaces</groupId>
            <artifactId>primefaces</artifactId>
            <version>6.2</version>
        </dependency>
        <dependency>
            <groupId>org.jboss.logging</groupId>
            <artifactId>jboss-logging</artifactId>
            <version>3.0.1.GA</version>
            <scope>compile</scope>
            <optional>true</optional>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.hibernate.javax.persistence/hibernate-jpa-2.1-api -->
        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.1-api</artifactId>
            <version>1.0.2.Final</version>
            <scope>provided</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/javax.enterprise/cdi-api -->
        <dependency>
            <groupId>javax.enterprise</groupId>
            <artifactId>cdi-api</artifactId>
            <version>2.0.SP1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.jboss.as</groupId>
            <artifactId>jboss-as-web</artifactId>
            <version>7.1.1.Final</version>
            <scope>compile</scope>
            <optional>true</optional>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.jboss.spec.javax.ejb/jboss-ejb-api_3.2_spec -->
        <dependency>
            <groupId>org.jboss.spec.javax.ejb</groupId>
            <artifactId>jboss-ejb-api_3.2_spec</artifactId>
            <version>1.0.2.Final</version>
            <scope>provided</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.google.cloud/google-cloud-translate -->
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-translate</artifactId>
            <version>1.61.0</version>
        </dependency>
        <dependency>
            <!-- jsoup HTML parser library @ https://jsoup.org/ -->
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.11.3</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.8.1</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>home.digest</finalName>
        <pluginManagement><!-- lock down plugins versions to avoid using Maven 
                defaults (may be moved to parent pom) -->
            <plugins>
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>3.1.0</version>
                </plugin>
                <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>3.2.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-install-plugin</artifactId>
                    <version>2.5.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-deploy-plugin</artifactId>
                    <version>2.8.2</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

如果我只像这样更改我的 TestServlet:

@WebServlet("/test")
public class TestServlet extends HttpServlet {

    @Inject
    private HomeToDealDBService homeToDealDBService;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException {
        try {
            HomeToDeal home = new HomeToDeal();
            home.setURL("alabale");
            homeToDealDBService.saveEntity(home);
        } catch (Exception e) {
            throw new ServletException(e);
        }
    }
}

虽然有效。可能是什么问题?

最佳答案

这种情况下的问题是注释

@TransactionAttribute(TransactionAttributeType.REQUIRED)

在方法之上

public void saveEntity(HomeToDeal homeToDeal) throws EntityExistsException{
    this.em.persist(homeToDeal);
}

在这种情况下,当从方法 ImmoweltBot.crawl() 调用时,saveEntity() 实际上是从同一事务中调用的,直到方法 ImmoweltBot.crawl() 完成。这就是为什么在事务结束之前没有将实体保存在数据库中的原因——意味着在 ImmoweltBot.crawl() 方法完成之前。使每个实体单独保存意味着将每个实体保存在它自己的事务中。如果我如下更改方法 saveEntity() 的注释,可能会发生这种情况:

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) 
public void saveEntity(HomeToDeal homeToDeal) throws EntityExistsException{
    this.em.persist(homeToDeal);
}

这实际上正是我想要的 - 如果特定实体的保存失败,这不会影响其余实体的保存。

关于mysql - JPA 实体未保存在数据库中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56721580/

相关文章:

java - JPA 数组映射

java - Spring Hibernate 在 Google App Engine 上给出 LazyInitializationException

java - Spring Boot 查询中的动态过滤器

java - Spring webflux : keeping an EntityManager open during the whole process of a reactive request handling

MySQL : can't set lower_case_table_names variable

php - 使用 WAMP 服务器设置 phpMyAdmin

java - hibernate in子句的限制是什么

java - JPA:@ManyToOne 关系的默认列名映射

mysql - 在联接表中使用 Max 选择

php - Laravel 不获取 MySQL 登录信息