I am trying to configure Atomikos Transaction without using spring.First i am trying to set up the EntityManagerFactory without using spring the following is code i have tried
private static AtomikosDataSourceBean prepareDataSource(){
AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
atomikosDataSourceBean.setUniqueResourceName("demo");
atomikosDataSourceBean.setXaDataSourceClassName("oracle.jdbc.xa.client.OracleXADataSource");
Properties properties = new Properties();
properties.setProperty("user", "demo");
properties.setProperty("password", "demo");
properties.setProperty("URL", "dbc:oracle:thin:#localhost:1521/xe");
atomikosDataSourceBean.setXaProperties(properties);
return atomikosDataSourceBean;
}
public static EntityManagerFactory getEntityManagerFactory(){
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setDataSource(prepareDataSource());
entityManagerFactory.setPersistenceUnitName("demo");
entityManagerFactory.setPersistenceXmlLocation("classpath*:META-INF/persistence.xml");
Properties properties = new Properties();
properties.setProperty("hibernate.transaction.jta.platform", "com.demo.AtomikosJtaPlatform");
properties.setProperty("hibernate.show_sql", "true");
return (EntityManagerFactory) entityManagerFactory;
}
The above code is returning me an classcastexception.How can i get the same entitymanagerfactory without using spring
I would refer to the official documentation of Atomikos, which actually contains an example for those who opt for not using Spring:
Atomikos without Spring
Related
I am playing with Camel 3.13.0 but it looks like the transaction is not rolled back when I use transacted. Any idea why?
The code snippet is below:
DataSource dataSource = InOutTest.setupDataSource();
//Initiate registry, transaction manager, policy
SimpleRegistry registry = new SimpleRegistry();
DataSourceTransactionManager transactionManager =
new DataSourceTransactionManager(dataSource);
registry.bind("transactionManager", transactionManager);
SpringTransactionPolicy propagationRequired =
new SpringTransactionPolicy();
propagationRequired.setTransactionManager(
transactionManager);
propagationRequired.setPropagationBehaviorName(
"PROPAGATION_REQUIRED");
registry.bind("PROPAGATION_REQUIRED", propagationRequired);
//Create context, add sql component
SqlComponent sqlComponent = new SqlComponent();
sqlComponent.setDataSource(dataSource);
CamelContext context = new DefaultCamelContext(registry);
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
context.addComponent("jmsComponent", JmsComponent.jmsComponentAutoAcknowledge(connectionFactory));
context.getComponent("sql", SqlComponent.class).setDataSource(InOutTest.setupDataSource());
context.addRoutes(new RouteBuilder() {
#Override
public void configure() throws Exception {
from("direct:sqlParam")
.transacted("PROPAGATION_REQUIRED")
.to("sql:insert into articles(name, category) values ('ActiveMQ', 'activemq')")
.process((exchange -> {throw new RuntimeException("Mock Ex");}));
}
});
Apache Camel has long have had the Transaction EIP pattern supported. One way to configure this pattern, is as you have already did through your Endpoint DSL configuration using transacted.
Meanwhile, you are attaching the PlatformTransationManager to a DataSource:
DataSourceTransactionManager transactionManager =
new DataSourceTransactionManager(dataSource);
Then you are configuring your SqlComponent to use a different DataSource:
context.getComponent("sql", SqlComponent.class).setDataSource(InOutTest.setupDataSource());
You should use the same managed DataSource used to configure your PlatformTransationManager by removing the aforementioned line and you should be good to go.
when there will be an issue with the external database for a live webapp and bean won't be able to get instantiated when retried again by the application then app goes down how can we fix this problem?
#Bean(destroyMethod = "close")
public DataSource dataSource(){
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setDriverClassName("com.mysql.jdbc.Driver");
hikariConfig.setJdbcUrl("jdbc:mysql://localhost:3306/spring-test");
hikariConfig.setUsername("root");
hikariConfig.setPassword("admin");
hikariConfig.setMaximumPoolSize(5);
hikariConfig.setConnectionTestQuery("SELECT 1");
hikariConfig.setPoolName("springHikariCP");
hikariConfig.addDataSourceProperty("dataSource.cachePrepStmts", "true");
hikariConfig.addDataSourceProperty("dataSource.prepStmtCacheSize", "250");
hikariConfig.addDataSourceProperty("dataSource.prepStmtCacheSqlLimit", "2048");
hikariConfig.addDataSourceProperty("dataSource.useServerPrepStmts", "true");
HikariDataSource dataSource = new HikariDataSource(hikariConfig);
return dataSource;
}
Your code will probably throw an exception if the datasource is down. Wrap it into try/catch like so:
try {
<your code goes here>
} catch (Exception e) {
return null;
}
But code calling for a datasource will have to accept the result may be null rather than throwing NullPointerExceptions.
I am facing an issue where my datasource bean is going down after a period of inactivity. My question is how could I re instantiate the datasource bean that gets hit on application startup.
Here is how we setup the bean on startup.
#ConfigurationProperties(prefix = "spring.datasource")
#Bean
public DataSource dataSource(){
byte[] encryptedFile = fileRetriever.getFile(bucket, key);
String unencryptedJson = fileDecrypter.decryptFile(encryptedFile);
JSONParser parser = new JSONParser();
JSONObject jsonObject = null;
try{
jsonObject = (JSONObject) parser.parse(unencryptedJson);
}catch (Exception ex){
log.error(ex.getMessage());
}
String password = (String)jsonObject.get("password");
DataSource ds = DataSourceBuilder
.create()
.url(url)
.username(userName)
.password(password)
.build();
return ds;
}
This class also has a #Configuration annotation on it.
We have other applications that do not have this issue where the service needs to be bounced after inactivity, but they are also not setting up the data source in this manner and have all the details specified in the application.property file
I have added a custom health check that uses a repository that hits every 30 seconds so that should keep the data source bean alive but incase it does go down I would need a way to recreate it.
Thanks in advance
I assume that boot is configuring the DataSource for you. In this case, and since you are using MySQL, you can add the following to your application.properties up to 1.3
spring.datasource.test-on-borrow=true
spring.datasource.validationQuery=SELECT 1
Might considered a pooled datasource connector. Look at apache dbcb2.
Here is a sample i have that keeps a minimum of 10 idle and increases as needed from the pool.
private static DataSource createDataSource(String url, String userName, String passwrd) throws Exception {
Class.forName(DRIVER).newInstance();
Properties props = new Properties();
props.setProperty("user", userName);
props.setProperty("password", passwrd);
//Create a connection factory that the pool will use to create connections
ConnectionFactory cf = new DriverManagerConnectionFactory(url, props);
//Create the poolable connection factory
PoolableConnectionFactory pcf = new PoolableConnectionFactory(cf, null);
pcf.setValidationQuery("SELECT 1");
pcf.setDefaultAutoCommit(true);
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
poolConfig.setMinIdle(10);
poolConfig.setMaxTotal(100);
AbandonedConfig abandonConfig = new AbandonedConfig();
abandonConfig.setRemoveAbandonedTimeout(60);
abandonConfig.setLogAbandoned(false);
abandonConfig.setRemoveAbandonedOnBorrow(true);
abandonConfig.setRemoveAbandonedOnMaintenance(true);
//Create the pool of connections
GenericObjectPool<PoolableConnection> connectionPool = new GenericObjectPool<>(pcf, poolConfig);
connectionPool.setTestOnBorrow(true);
connectionPool.setTestWhileIdle(true);
connectionPool.setTimeBetweenEvictionRunsMillis(10000);
connectionPool.setMinEvictableIdleTimeMillis(1000);
connectionPool.setAbandonedConfig(abandonConfig);
pcf.setPool(connectionPool);
//Pooling data source itself
PoolingDataSource<PoolableConnection> dataSource = new PoolingDataSource<>(connectionPool);
return dataSource;
}
Maven dependencies for apache dbcb2
<!-- Database connection pools -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.4.2</version>
</dependency>
I am setting up my DataSource in a Spring Boot / Spring Cloud Connectors project running on Cloud Foundry using Tomcat JDBC Connection Pool and MariaDB JDBC driver like so:
#Configuration
#Profile("cloud")
public class MyDataSourceConfiguration extends AbstractCloudConfig {
#Bean
public DataSource dataSource() {
Map<String, Object> dataSourceProperties = new HashMap<>();
dataSourceProperties.put("initialSize", "4"); // OK
dataSourceProperties.put("maxActive", "4"); // OK
dataSourceProperties.put("maxWait", "2000"); // OK
dataSourceProperties.put("connectionProperties",
"useUnicode=yes;characterEncoding=utf8;"); // ignored
DataSourceConfig conf = new DataSourceConfig(dataSourceProperties);
return connectionFactory().dataSource(conf);
}
}
For some reason only the properties referring to the pool size and maxWait but not the connectionProperties are getting picked up by the DataSource bean - see the log output:
maxActive=4; initialSize=4; maxWait=2000;
connectionProperties=null
Any hints ?
Note: Trying to set the connectionProperties via Spring's ConnectionConfig class didn't work either.
Try using the form of DataSourceConfig that takes separate PoolConfig and ConnectionConfig beans, like this:
#Bean
public DataSource dataSource() {
PoolConfig poolConfig = new PoolConfig(4, 4, 2000);
ConnectionConfig connectionConfig = new ConnectionConfig("useUnicode=yes;characterEncoding=utf8;");
DataSourceConfig dbConfig = new DataSourceConfig(poolConfig, connectionConfig);
return connectionFactory().dataSource(dbConfig);
}
Try the following:
Replace
connProperties.put("connectionProperties", "useUnicode=yes;characterEncoding=utf8;");
with
connProperties.put("connectionProperties", "useUnicode=yes;characterEncoding=UTF-8;");
Alternately, you can also specify the following property directly in application.properties
spring.datasource.connectionProperties=useUnicode=true;characterEncoding=utf-8;
I want my H2 database to be stored into a file, so that once I close the application and open it again, all the data that was previously written to the database is still there, but for some reason, at the moment whenever I start the application, the database is completely empty. Any suggestions?
#Bean
public DataSource dataSource() {
File f = new File(".");
JdbcDataSource ds = new JdbcDataSource();
ds.setURL("jdbc:h2:file:" + f.getAbsolutePath() + "/db/aurinko");
ds.setUser("");
ds.setPassword("");
return ds;
}
private Properties getHibernateProperties() {
Properties prop = new Properties();
prop.put("hibernate.format_sql", "true");
prop.put("hibernate.show_sql", "false");
prop.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
prop.put("hibernate.hbm2ddl.auto", "update");
return prop;
}
#Bean
public SessionFactory sessionFactory() throws IOException {
LocalSessionFactoryBuilder builder = new LocalSessionFactoryBuilder(dataSource());
builder.scanPackages("io.aurinko.server.jpa").addProperties(getHibernateProperties());
SessionFactory result = builder.buildSessionFactory();
return result;
}
I was using spring-boot. Turns out that spring-boot generates its own H2 database. That means that I had two separate databases, one of which I was trying to use and the second one (only the in-memory one) that I was actually using.
May be try setting auto commit to true in the config/ property file. It may work