I'm trying to configure Spring Boot to use 2 datasources using JNDI:
application.properties:
spring.production.datasource.jndi-name=java:/global/production_gateway
spring.production.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.production.datasource.jpa.properties.hibernate.dialect=org.hibernate.dialect.MariaDBDialect
spring.production.datasource.jpa.show-sql = true
spring.production.datasource.jpa.hibernate.ddl-auto = update
spring.warehouse.datasource.jndi-name=java:/global/production_warehouse
spring.warehouse.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.warehouse.datasource.jpa.properties.hibernate.dialect=org.hibernate.dialect.MariaDBDialect
spring.warehouse.datasource.jpa.show-sql = true
spring.warehouse.datasource.jpa.hibernate.ddl-auto = update
Primary datasource:
#Configuration
#EnableJpaRepositories(
basePackages = "org.datalis.plugin.production.entity",
entityManagerFactoryRef = "productionEntityManager",
transactionManagerRef = "productionTransactionManager"
)
#EnableTransactionManagement
public class ContextProductionDatasource {
#Primary
#Bean(name = "productionDataSourceProperties")
#ConfigurationProperties(prefix="spring.production.datasource")
public JndiPropertyHolder productionDataSourceProperties() {
return new JndiPropertyHolder();
}
#Primary
#Bean(name = "productionDataSource")
#ConfigurationProperties(prefix="spring.production.datasource")
public DataSource productionDataSource() {
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
DataSource dataSource = dataSourceLookup.getDataSource(productionDataSourceProperties().getJndiName());
return dataSource;
}
#Primary
#Bean(name = "productionEntityManager")
public EntityManager productionEntityManager(EntityManagerFactory emf) {
return emf.createEntityManager();
}
#Primary
#PersistenceContext(unitName = "production")
#Bean(name = "productionLocalEntityManager")
public LocalContainerEntityManagerFactoryBean mySqlEntityManagerFactory(EntityManagerFactoryBuilder builder) {
return builder.dataSource(productionDataSource()).persistenceUnit("production").packages("org.datalis.plugin.production.entity").build();
}
#Primary
#Bean(name = "productionTransactionManager")
public PlatformTransactionManager productionTransactionManager(final EntityManagerFactory emf) {
final JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
#Primary
#Bean(name = "productionExceptionTranslation")
public PersistenceExceptionTranslationPostProcessor productionExceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
private static class JndiPropertyHolder {
private String jndiName;
public String getJndiName() {
return jndiName;
}
public void setJndiName(String jndiName) {
this.jndiName = jndiName;
}
}
}
I try to use the entity manager this way:
#Service
#Transactional(value = "productionEntityManager")
public class ..... {
#PersistenceContext(unitName = "production")
private EntityManager entityManager;
}
But I get an error during deployment:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available
Do you know where my configuration is wrong?
You seem to be missing a bean for EntityManagerFactory. You're requesting it here:
public EntityManager productionEntityManager(EntityManagerFactory emf) {
Try adding
#Primary
#Bean(name = "productionEntityManagerFactory")
public EntityManagerFactory productionEntityManagerFactory() {
return Persistence.createEntityManagerFactory("production");
}
Related
There are two data source configuration classes:
#Configuration
#EnableJpaRepositories(
basePackages = {"com.proj.killbill.repository.kb", "com.proj.service.base.repository"},
entityManagerFactoryRef = "kbEntityManagerFactory",
transactionManagerRef = "kbTransactionManager")
#EnableJpaAuditing
#Profile({"dev", "prod"})
public class PersistenceKbConfig {
#Value("${db.user:default}")
private String user;
#Value("${db.password:default}")
private String password;
#Value("${db.url:default}")
private String jdbcUrl;
#Value("${app.kb.ds.jndi.name}")
private String kbDsJndiName;
#Bean(name = "kbDataSource")
#Profile("dev")
public DataSource devKbDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
dataSource.setUrl(jdbcUrl);
dataSource.setUsername(user);
dataSource.setPassword(password);
return dataSource;
}
#Bean(name = "kbDataSource")
#Profile("prod")
public DataSource prodKbDataSource() {
final JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
dsLookup.setResourceRef(true);
return dsLookup.getDataSource(kbDsJndiName);
}
#SuppressWarnings("Duplicates")
#Bean(name = "kbEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
#Qualifier("kbDataSource") DataSource dataSource) {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource);
em.setPackagesToScan("com.proj.service.base.domain");
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
private Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.Oracle10gDialect");
return properties;
}
#Bean(name = "kbTransactionManager")
public PlatformTransactionManager kbTransactionManager(
#Qualifier("kbEntityManagerFactory") EntityManagerFactory emf) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
}
#Configuration
#EnableJpaRepositories(
basePackages = {"com.proj.killbill.repository.cm", "com.proj.service.base.repository"},
entityManagerFactoryRef = "cmEntityManagerFactory",
transactionManagerRef = "cmTransactionManager")
#EnableJpaAuditing
#Profile({"dev", "prod"})
public class PersistenceCmConfig {
#Value("${cm.db.user:default}")
private String user;
#Value("${cm.db.password:default}")
private String password;
#Value("${cm.db.url:default}")
private String jdbcUrl;
#Value("${app.cm.ds.jdni.name}")
private String cmJndiName;
private static final Logger LOGGER = LogManager.getLogger(PersistenceCmConfig.class);
#Bean(name = "cmDataSource")
#Profile("dev")
public DataSource devCmDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
dataSource.setUrl(jdbcUrl);
dataSource.setUsername(user);
dataSource.setPassword(password);
LOGGER.debug("CM JDBC URL USER/PASSWORD" + jdbcUrl + " " + user + "/" + password);
return dataSource;
}
#Bean(name = "cmDataSource")
#Profile("prod")
public DataSource prodCmDataSource() {
final JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
dsLookup.setResourceRef(true);
return dsLookup.getDataSource(cmJndiName);
}
#SuppressWarnings("Duplicates")
#Bean(name = "cmEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean cmEntityManagerFactory(
#Qualifier("cmDataSource") DataSource dataSource) {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource);
em.setPackagesToScan("com.proj.service.base.domain");
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
private Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.Oracle10gDialect");
return properties;
}
#Bean(name = "cmTransactionManager")
public PlatformTransactionManager cmTransactionManager(
#Qualifier("cmEntityManagerFactory") EntityManagerFactory emf) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
}
Entity managers use #Qualifier annotations to inject appropriate data sources. But when I start the app I get the exception:
==========
Parameter 0 of method cmEntityManagerFactory in com.proj.killbill.config.PersistenceCmConfig required a single bean, but 2 were found:
- cmDataSource: defined by method 'devCmDataSource' in class path resource [com/proj/killbill/config/PersistenceCmConfig.class]
- kbDataSource: defined by method 'devKbDataSource' in class path resource [com/proj/killbill/config/PersistenceKbConfig.class]
Action:
Consider marking one of the beans as #Primary, updating the consumer to accept multiple beans, or using #Qualifier to identify the bean that should be consumed
============
#Qualifier("cmDataSource") is just ignored for unknown reason. Why can it be possible?
Im trying to use Spring and JPA. I have a table in Oracle of which few of the fields are RAW(16 BYTE) type. My entity looks like following:
#Entity
#Table(name = "testTable")
public class TestTable implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "ID")
#Type(type = "uuid-binary")
private UUID id;
#Column(name = "TABLE_ID")
#Type(type = "uuid-binary")
private UUID tableId;
#Column(name = "STATUS")
private String status;
My repository class looks like the following:
#Repository
public interface TestRepository extends JpaRepository<TestTable, UUID> {
TestTable getTestTableByTableId(#Param("table_id") UUId table_id);
}
The column i'm trying to mark as #Param is not primary key. I have enabled JPA Repositories on configuration file with #EnableJpaRepositories as follows:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackageClasses = { TestRepository.class })
#EnableJpaAuditing
public class JpaConfig {
#Bean(name="entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
Map<String, Object> jpaProperties = new HashMap<>();
jpaProperties.put("eclipselink.weaving", "false");
jpaProperties.put("eclipselink.logging.parameters", "true");
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(this.getDataSource());
entityManagerFactoryBean.setPackagesToScan("com.test.entity");
entityManagerFactoryBean.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver());
entityManagerFactoryBean.setJpaVendorAdapter(this.vendorAdapter());
entityManagerFactoryBean.setJpaPropertyMap(jpaProperties);
return entityManagerFactoryBean;
}
#Bean
public JpaVendorAdapter vendorAdapter() {
EclipseLinkJpaVendorAdapter vendorAdapter = new EclipseLinkJpaVendorAdapter();
vendorAdapter.setDatabase(Database.ORACLE);
vendorAdapter.setShowSql(true);
return vendorAdapter;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
#Bean
public DriverManagerDataSource getDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
//datasource properties here
return dataSource;
}
#Bean()
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(this.entityManagerFactoryBean().getObject());
return transactionManager;
}
when i autowire the repository in my controller and invoke the method defined in the repository, JPA creates SQL in the background and tried to bind the parameter, but it is binding an object reference instead of UUID as follows:
[EL Fine]: sql: 2016-08-10 09:17:22.306--ServerSession(1292029763)--Connection(678757862)--SELECT ID, TABLE_ID, STATUS FROM TESTTABLE WHERE (TABLE_ID= ?)
bind => [[B#2f6964a4]
My question is why is it binding it as an object? and how would I resolve it? thanks in advance.
I have the following configuration:
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackageClasses = DemoApplication.class)
public class JpaConfig implements TransactionManagementConfigurer {
#Value("${dataSource.driverClassName}")
private String driver;
#Value("${dataSource.url}")
private String url;
#Value("${dataSource.username}")
private String username;
#Value("${dataSource.password}")
private String password;
#Value("${hibernate.dialect}")
private String dialect;
#Value("${hibernate.hbm2ddl.auto}")
private String hbm2ddlAuto;
#Bean
public DataSource configureDataSource() {
HikariConfig config = new HikariConfig();
config.setDriverClassName(driver);
config.setJdbcUrl(url);
config.setUsername(username);
config.setPassword(password);
return new HikariDataSource(config);
}
#Bean
public LocalContainerEntityManagerFactoryBean configureEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(configureDataSource());
entityManagerFactoryBean.setPackagesToScan("com.dataart.cashmashine");
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
Properties jpaProperties = new Properties();
jpaProperties.put(org.hibernate.cfg.Environment.DIALECT, dialect);
jpaProperties.put(org.hibernate.cfg.Environment.HBM2DDL_AUTO, hbm2ddlAuto);
entityManagerFactoryBean.setJpaProperties(jpaProperties);
return entityManagerFactoryBean;
}
#Bean
public PlatformTransactionManager annotationDrivenTransactionManager() {
return new JpaTransactionManager();
}
#Bean
public SessionFactory sessionFactory(HibernateEntityManagerFactory hemf) {
return hemf.getSessionFactory();
}
}
application.properties:
dataSource.driverClassName=org.postgresql.Driver
dataSource.url=jdbc:postgresql://localhost:5432/cash_mashine
dataSource.username=marc
dataSource.password=marc
hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
hibernate.hbm2ddl.auto=create-drop
In dao I write following rows:
#Autowired
private SessionFactory sessionFactory;
#Override
public CreditCard findCard(String cardNumber) {
Session currentSession = sessionFactory.getCurrentSession();
when executes
sessionFactory.getCurrentSession()
I see following error:
Caused by: org.hibernate.HibernateException: No CurrentSessionContext
configured!
How to fix this?
spring:
jpa:
properties:
hibernate:
current_session_context_class: org.springframework.orm.hibernate5.SpringSessionContext
above config in application.yml can solve this problem.
Try adding #Transactional at a public service method which is invoking the DAO.
I have got No transactional EntityManager available exception when I tried to persist an object.
I have a Spring project with the following configuration class:
#Configuration
#ComponentScan
#EnableTransactionManagement
#EnableJpaRepositories
public class SpringConfiguration {
#Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean emf(DataSource dataSource) {
LocalContainerEntityManagerFactoryBean emf =new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(dataSource);
Properties jpaProperties = new Properties();
jpaProperties.put("hibernate.hbm2ddl.auto", "create-drop");
jpaProperties.put("hibernate.show_sql", "true");
emf.setJpaProperties(jpaProperties);
emf.setPackagesToScan(
new String[] {"ds.core.entity"});
emf.setJpaVendorAdapter(
new HibernateJpaVendorAdapter());
return emf;
}
#Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager(EntityManagerFactory emf,DataSource dataSource) {
JpaTransactionManager tm =
new JpaTransactionManager();
tm.setEntityManagerFactory(emf);
tm.setDataSource(dataSource);
return tm;
}
And an entity class:
#Entity
public class Type {
#Id #GeneratedValue
private Long id;
private String name;
}
and Jpa implementation class :
#Repository
public class JpaTypeRepo implements TypeRepo {
#PersistenceContext
private EntityManager em;
#Override
public Type insertRecord(Type data) {
em.persist(data);
return data;
}
}
And finally a Service Class with Init():
#Transactional
#Service
public class InitDbService {
#Autowired
private TypeRepo typeRepo;
#PostConstruct
public void init() {
Type type=new Type();
type.setName("newName");
typeRepo.insertRecord(type);
}}
just add #Transactional annotation to the class :JpaTypeRepo
as following:
#Transactional
#Repository
public class JpaTypeRepo implements TypeRepo {
#PersistenceContext
private EntityManager em;
#Override
public Type insertRecord(Type data) {
em.persist(data);
return data;
}
}
here are my 3 classes:
#Configuration //Marks this class as configuration
//Specifies which package to scan
#ComponentScan({"pl.jpet"})//,"pl.dup"})
//Enables Spring's annotations
#EnableWebMvc
//#EnableTransactionManagement
#PropertySource("classpath:application.properties")
public class Config {
#Resource
private Environment env;
#Bean(name = "dataSource")
public BasicDataSource dataSource() {
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/wikidb");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
#Bean
public HibernateExceptionTranslator hibernateExceptionTranslator() {
return new HibernateExceptionTranslator();
}
#Bean
#Autowired
public EntityManagerFactory entityManagerFactory(BasicDataSource dataSource) {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setDatabasePlatform("org.hibernate.dialect.MySQL5InnoDBDialect");
vendorAdapter.setDatabase(Database.MYSQL);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setDataSource(dataSource);
factory.setPersistenceUnitName("wikidb");
factory.setPackagesToScan("pl.jpet");
factory.afterPropertiesSet();
return factory.getObject();
}
#Bean
#Autowired
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager txManager = new JpaTransactionManager();
JpaDialect jpaDialect = new HibernateJpaDialect();
txManager.setEntityManagerFactory(entityManagerFactory);
txManager.setJpaDialect(jpaDialect);
return txManager;
}
----------------------------------------------------------------------
package pl.jpet.model;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Data
#Table(name="zrobmitabele")
public class TestModel {
#Id
#Column(name = "name", nullable = false)
private String name;
}
-----------------------------------------------------------------------------
#Transactional
#RestController
#RequestMapping("/una")
public class UnauthenticatedController {
#PersistenceContext
private EntityManager em;
#Transactional
#RequestMapping(method = RequestMethod.GET,value="/checkLogin")
public ResponseEntity<String> checkLogin() throws IOException {
TestModel test = new TestModel();
test.setName("KUBA");
em.persist(test);
return new ResponseEntity<String>(HttpStatus.OK);
}
}
I'm getting this info on start "INFO [org.hibernate.cfg.Environment] (MSC service thread 1-1) HHH000206: hibernate.properties not found" but still it's not crushing, even after I'm making call to "/una" service it's not throwing anything - Guess there's something wrong with my Config class but i have no idea what, anyone ?
I missed #EnableTransactionManagement on my config class
#_#