我有一个使用 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; 

我的 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); 
} 

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


评论关闭
IT序号网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!