注入两个@PersistenceContext之一

时间:2018-09-26 14:29:57

标签: spring hibernate jpa

考虑有两个实体管理器工厂:

<bean id="writeEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">...</bean>
<bean id="readOnlyEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">...</bean>

然后我想要有两个Bean,可以向它们注入正确的持久性上下文:

<bean id="readOnlyManager" class="..MyDatabaseManager">
<bean id="writeManager" class="..MyDatabaseManager">

bean看起来像:

public class MyDatabaseManager {

    private javax.persistence.EntityManager em;

    public EntityManager(javax.persistence.EntityManager em) {
        this.em = em;
    }
    ...
}

这显然是行不通的,因为EntityManager不是bean,并且不能以这种方式注入:

No qualifying bean of type 'javax.persistence.EntityManager' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

如何在Bean中限定正确的EntityManager?我曾经使用@PersistenceContext批注,但这无法使用,因为我需要注入它。

如何为此类Bean指定PersistenceContext?

更新:我的问题是如何通过XML而不是通过注释将PersistenceContext与限定符一起插入。

3 个答案:

答案 0 :(得分:1)

persistence.xml(2个不同的entitymanager的2个持久性单元,根据您在这里使用HibernatePersistence的持久性提供程序)

#include<iostream>
#include<vector>
#include<climits>
#include<cstring>
#include<algorithm>
using namespace std;

// Basic structure for the given problem
struct Item {
    float weight;
    float volume;

    Item(float weight, float volume) {
        this->weight = weight;
        this->volume = volume;
    }

    bool operator<(const Item &other) const {
        if(weight == other.weight) {
            return volume < other.volume;
        }
        return weight < other.weight;
    }
};

// Some constant values
const static int INF = INT_MAX / 100;
const static int MAX_NUM_OF_ITEMS = 1000;
const static int MAX_N = 1000;

// Parameters that we define in main()
float MAX_VOLUME;
vector<Item> items;

// DP lookup tables
int till[MAX_NUM_OF_ITEMS];
float dp[MAX_NUM_OF_ITEMS][MAX_N];

/**
 * curIndex: the starting index from where we aim to formulate a new group
 * left: number of groups still left to be formed
 */ 
float solve(int curIndex, int left) {
    // Baseline condition
    if(curIndex >= items.size() && left == 0) {
        return 0;
    }
    if(curIndex >= items.size() && left != 0) {
        return INF;
    }
    // If we have no more groups to be found, but there still are items left
    // then invalidate the solution by returning INF
    if(left <= 0 && curIndex < items.size()) {
        return INF;
    }

    // Our lookup dp table
    if(dp[curIndex][left] >= 0) {
        return dp[curIndex][left];
    }

    // minVal is the metric to optimize which is the `sum of the differences
    // for each group` we intialize it as INF
    float minVal = INF;

    // The volume of the items we're going to pick for this group
    float curVolume = 0;

    // Let's try to see how large can this group be by trying to expand it 
    // one item at a time
    for(int i = curIndex; i < items.size(); i++) {
        // Verfiy we can put the item i in this group or not
        if(curVolume + items[i].volume > MAX_VOLUME) {
            break;
        }
        curVolume += items[i].volume;
        // Okay, let's see if it's possible for this group to exist
        float val = (items[i].weight - items[curIndex].weight) + solve(i + 1, left - 1);
        if(minVal >= val) {
            minVal = val;
            // The lookup table till tells that the group starting at index
            // curIndex, expands till i, i.e. [curIndex, i] is our valid group
            till[curIndex] = i + 1;
        }
    }
    // Store the result in dp for memoization and return the value
    return dp[curIndex][left] = minVal;
}

int main() {
    // The maximum value for Volume
    MAX_VOLUME = 6;
    // The number of groups we need
    int NUM_OF_GROUPS = 5;

    items = vector<Item>({
    // Item(weight, volume)
        Item(5, 2),
        Item(2, 1),
        Item(10, 3),
        Item(7, 2),
        Item(3, 1),
        Item(5, 3),
        Item(4, 3),
        Item(3, 2),
        Item(10, 1),
        Item(11, 3),
        Item(19, 1),
        Item(21, 2)
    });

    // Initialize the dp with -1 as default value for unexplored states
    memset(dp, -1, sizeof dp);

    // Sort the items based on weights first
    sort(items.begin(), items.end());

    // Solve for the given problem
    int val = solve(0, NUM_OF_GROUPS);

    // If return value is INF, it means we couldn't distribute it in n
    // groups due to the contraint on volume or maybe the number of groups
    // was greater than the number of items we had ^_^
    if(val >= INF) {
        cout << "Not possible to distribute in " << NUM_OF_GROUPS;
        return 0;
    }

    // If a solution exists, use the lookup till array to find which items
    // belong to which set  
    int curIndex = 0, group = 1;
    while(curIndex < items.size()) {
        cout << "Group #" << group << ": ";
        for(int i = curIndex; i < till[curIndex]; i++)
            cout << "(" << items[i].weight << ", " << items[i].volume << ") ";
        cout << '\n';
        group++;    
        curIndex = till[curIndex];
    }
}

确保使用属性persistenceUnitName将持久性单元分配给实体管理器

<persistence version="2.0" 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_2_0.xsd">
   <persistence-unit name="pu1">
      <provider>org.hibernate.ejb.HibernatePersistence</provider>
   </persistence-unit>

   <persistence-unit name="pu2">
      <provider>org.hibernate.ejb.HibernatePersistence</provider>
   </persistence-unit>   
</persistence>

与其他em相同。

现在,对MyDatabaseManager使用构造函数注入来注入EntityManager(使用限定符名称,例如writeEntityManagerFactory)

    <bean id="writeEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
            <property name="persistenceXmlLocation" value="classpath: of yout persistence xml" />
            <property name="persistenceUnitName" value="pu1" />  
             .....other configuration of em..  
    </bean>

答案 1 :(得分:0)

假设您正在使用spring来管理事务,那么我要做的是2个不同的事务管理器,然后在我的服务中,我将使用像这样的最合适的事务管理器:

“配置”部分

@Bean
public LocalContainerEntityManagerFactoryBean writeEntityManagerFactory() {

    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
    //Your configuration here
    return factory;
}

@Bean(name={"writeTx"})
public PlatformTransactionManager writeTransactionManager() {

    JpaTransactionManager txManager = new JpaTransactionManager();
    txManager.setEntityManagerFactory(writeEntityManagerFactory().getObject());
    return txManager;
}

@Bean
public LocalContainerEntityManagerFactoryBean readEntityManagerFactory() {

    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
    //Your configuration here
    return factory;
}

@Bean(name={"readTx"})
public PlatformTransactionManager readTransactionManager() {

    JpaTransactionManager txManager = new JpaTransactionManager();
    txManager.setEntityManagerFactory(readEntityManagerFactory().getObject());
    return txManager;
}

服务层

@Transactional(value="readTx")
public List<Object> read(){
    //Your read code here
}

@Transactional(value="writeTx")
public void write(){
    //Your write code here
}

更新后的答案 我误解了这个问题。

在配置类中,您可以定义:

@Bean
    public LocalContainerEntityManagerFactoryBean writeEntityManagerFactory() {

        LocalContainerEntityManagerFactoryBean em  = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource());
        em.setPackagesToScan(new String[] { "models" });
        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        em.setJpaProperties(hibProps());
        em.setPersistenceUnitName("writer");
        return em;
    }
    @Bean
    public LocalContainerEntityManagerFactoryBean readEntityManagerFactory() {

        LocalContainerEntityManagerFactoryBean em  = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource());
        em.setPackagesToScan(new String[] { "models" });
        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        em.setJpaProperties(hibProps());
        em.setPersistenceUnitName("reader");
        return em;
    }   

请查看PersistenceUnitName

然后您可以通过以下方式注入它们:

@PersistenceContext(unitName="writer")
private EntityManager emWriter;

@PersistenceContext(unitName="reader")
private EntityManager emReader;

我刚刚对其进行了测试,并且效果都很好

天使

答案 2 :(得分:0)

我想你正试图将一个 entityManager 注入你的经理类

public class MyDatabaseManager {

// where you need to qualify your injection    
private javax.persistence.EntityManager em;

    public EntityManager(javax.persistence.EntityManager em) {
        this.em = em;
    }
    ...
}

这是我的项目的工作代码

  1. META-INF 文件夹中的 Persistence.xml

     <persistence version="1.0" 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">
         <persistence-unit name="PERSISTENCE_UNIT_T" transaction-type="JTA">
             <provider>foo.bar.PersistenceProvider</provider>
             <jta-data-source>jdbc/DB2</jta-data-source>
    
         </persistence-unit>
    
          <persistence-unit name="PERSISTENCE_UNIT_P" transaction-type="JTA">
             <provider>foo.bar.PersistenceProvider</provider>
             <jta-data-source>jdbc/DB2</jta-data-source>
    
         </persistence-unit> 
     </persistence>
    
  2. 限定符接口类 SelectDataSource

<块引用>
 @Qualifier
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD })
    public @interface SelectDataSource{}
  1. EntityManager 类

    公共类EntityManager{

         public EntityManager() {
         }
    
         @Inject
         @SelectDataSource
         private EntityManager entityManager;
    
         // other entity manager methods
    
     }
    
  2. Entity Manager Provider 类提供基于上下文的持久化单元

    公共类 EntityManagerProvider {

         @PersistenceContext(unitName = "PERSISTENCE_UNIT_T")
         private EntityManager entityManagerT;
    
         @PersistenceContext(unitName = "PERSISTENCE_UNIT_P")
         private EntityManager entityManagerP;
    
    
         @Produces
         @SelectDataSource
         EntityManager createEntityManager(InjectionPoint injectionPoint) {
    
             if (System.ENV.equalsIgnoreCase("p")) {
                 if (entityManagerP != null) {
    
                     return entityManagerP;
                 }
             }
    
             return entityManagerT;
         }
    
     }
    

然后可以使用 @Inject

将 EntityManager 类注入到您喜欢的任何位置

下面是一篇关于如何使用上下文依赖注入创建托管实体管理器的好文章 https://www.sitepoint.com/cdi-weld-inject-jpa-hibernate-entity-managers/#usingaproducermethod