How to use Spring Transaction when using GenericApplicationContext - spring

When using Distributed Mysql Database, I've Created multiple dataSources, sessionFactory using BeanDefinitionBuilder
But transactional annotation doesn't seem to work when I execute Insert SQL
using getBean('bean name') method below
( (SqlSessionTemplate)context.getBean('bean name') ).insert("xxxx",params)
Would you explain what I've missed?
Private GenericApplicationContext context = new GenericApplicationContext();
BeanDefinitionBuilder sessionFactoryBuilder = BeanDefinitionBuilder.rootBeanDefinition(org.mybatis.spring.SqlSessionFactoryBean.class);
sessionFactoryBuilder.addPropertyReference("dataSource", "dataSource" + beanName);
sessionFactoryBuilder.addPropertyValue("configLocation", "/sqlmap.xml");
context.registerBeanDefinition("sqlSessionFactory" + beanName, sessionFactoryBuilder.getBeanDefinition());
BeanDefinitionBuilder transactionManagerBuilder = BeanDefinitionBuilder.rootBeanDefinition(org.springframework.jdbc.datasource.DataSourceTransactionManager.class);
transactionManagerBuilder.addPropertyReference("dataSource", "dataSource" + beanName);
context.registerBeanDefinition("transactionManager",transactionManagerBuilder.getBeanDefinition());
ctx.refresh();

Please try to add the following codes below and see if it works.
ConfigurableListableBeanFactory factory = context.getBeanFactory();
AspectJAwareAdvisorAutoProxyCreator aspectJPostProcessor = new AspectJAwareAdvisorAutoProxyCreator();
aspectJPostProcessor.setBeanFactory( factory );
aspectJPostProcessor.setProxyClassLoader( context.getClassLoader() );
factory.addBeanPostProcessor(aspectJPostProcessor);

Related

about spring applicationContext

i learned that when spring applicationContext is created,
context itself will be registered as bean.
so i made a simple code and expect applicationContext as a bean.
However, when i create applicationContext with java-code like below,
i couldn't see applicationContext as a bean..
====code====
ApplicationContext parent = new GenericXmlApplicationContext(basePath + "parentContext.xml");
GenericApplicationContext child = new GenericApplicationContext(parent);
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(child);
reader.loadBeanDefinitions(basePath+"childContext.xml");
child.refresh();
Printer printer = child.getBean("printer",Printer.class);
assertNotNull(printer);
for(String bean : parent.getBeanDefinitionNames()) {
System.out.println("TTTT : "+ bean +" : "+parent.getBean(bean).getClass().getName());
}
=====================
i both tried with parent and child. could anyone can explain why applicationContext itself is not
registered as a bean?
I would try adding this line to parentContext.xml:
<import resource="contextSub.xml"/>
and in the java code add this annotation
#Before
public void setup(){
ApplicationContext parent = new GenericXmlApplicationContext(basePath + "parentContext.xml");
GenericApplicationContext child = new GenericApplicationContext(parent);
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(child);
reader.loadBeanDefinitions(basePath+"childContext.xml");
child.refresh();
Printer printer = child.getBean("printer",Printer.class);
assertNotNull(printer);
for(String bean : parent.getBeanDefinitionNames()) {
System.out.println("TTTT : "+ bean +" : "+parent.getBean(bean).getClass().getName());
}
Let me know if this helps.

#Transactional annotation with spring and getting current co

I have a method which has a UPDATE query and a select query. I annotated the method with #Transactional for the below use case.
For concurrent executions - if two users are updating the same table ,I need the update and select query to be run as a unit
If not using #Transactional , I am using jdbc template and i am trying to get the current connection set auto commit to false and commit to true at the end of the method
Issue 1:
Update is getting commited immediately after the statement is executed
Issue 2:
With jdbc template , unable to get the current connection used for transaction .
I have tried the below two ways to get the current connection , but it seems to be a new connection from the pool
1.Connection conn = DataSourceUtils.getConnection(template.getDataSource());
2.Connection con=template.getDataSource().getConnection();
Application deployed in WebLogic Server using using java configuration , created bean for jdbc template , datasource and transaction management and used autowiring
#Transactional
public Integer getNextId(String tablename) {
Integer nextId = null;
int swId = template.update("update " + tablename + " set swId = swId + 1");
//int swId1 = template.update("update " + tablename + " set swId = swId + 1");
if (swId == 1) {
nextId = template.queryForObject("select swId from " + tablename,
int.class);
}
return nextId;
}
}
#Scope("prototype")
#Bean
public DataSource dataSource() throws NamingException {
javax.naming.InitialContext ctx = new javax.naming.InitialContext();
DataSource dataSource = (javax.sql.DataSource) ctx.lookup(dsnName);
return dataSource;
}
#Scope("prototype")
#Bean
public DataSourceTransactionManager dataSourceTransactionManager(DataSource dataSource) {
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
#Scope("prototype")
#Bean
public JdbcTemplate template(DataSource dataSource) {
JdbcTemplate template = new JdbcTemplate(dataSource);
return template;
}
Expected results.
Commit should happen after all the statements in the method is executed
jdbc template need to get the active connection sed for current transaction

hibernate 5 and spring - generate ddl using SchemaExport

In hibernate 4 - spring 4 setup it was possible to generate DDL using SchemaExport object:
LocalSessionFactoryBean sfb = (LocalSessionFactoryBean) context.getBean("&sessionFactory");
SchemaExport schema = new SchemaExport(sfb.getConfiguration());
But hibernate 5 replaces SchemaExport(Configuration configuration) constructor with SchemaExport(MetadataImplementator metadataImplementator).
MetadataImplementator is not readily available on
org.springframework.orm.hibernate5.LocalSessionFactoryBean or org.springframework.orm.hibernate5.LocalSessionFactoryBuilder
I hacked it like this:
MetadataSources metadataSources = (MetadataSources) FieldUtils.readField(configuration, "metadataSources", true);
Metadata metadata = metadataSources
.getMetadataBuilder(configuration.getStandardServiceRegistryBuilder().build())
.applyPhysicalNamingStrategy(new MyPhysicialNamingStrategy())
.applyImplicitNamingStrategy(ImplicitNamingStrategyJpaCompliantImpl.INSTANCE)
.build();
MetadataImplementor metadataImpl = (MetadataImplementor) metadata;
SchemaExport schema = new SchemaExport(metadataImplementor);
But it would be nice to have a better way and also, Validator annotations (#NotNull, #Size) are not used for DDL generation and I don't know if it is a bug in Hibernate 5 or this setup.
I am using hibernate 5.0.0.CR4 and spring 4.2.0.RELEASE
You need to implement org.hibernate.integrator.spi.Integrator where you can store required data to some holder.
Work example you can find here https://github.com/valery-barysok/spring4-hibernate5-stackoverflow-34612019
register it as the service at META-INF/services/org.hibernate.integrator.spi.Integrator file
public class Integrator implements org.hibernate.integrator.spi.Integrator {
#Override
public void integrate(Metadata metadata, SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
HibernateInfoHolder.setMetadata(metadata);
HibernateInfoHolder.setSessionFactory(sessionFactory);
HibernateInfoHolder.setServiceRegistry(serviceRegistry);
}
#Override
public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
}
}
Use it
new SchemaExport((MetadataImplementor) HibernateInfoHolder.getMetadata()).create(true, true);
new SchemaUpdate(HibernateInfoHolder.getServiceRegistry(), (MetadataImplementor) HibernateInfoHolder.getMetadata()).execute(true, true);
Additional info you can find here Programmatic SchemaExport / SchemaUpdate with Hibernate 5 and Spring 4
There is Configuration over Convention principle for Java Persistence API but Validation API is intended for validation purpose only. Validation is not absolute you can put different validation rules on the same field.
if you have for example
#Size(max = 50)
#NotNull(groups = DefaultGroup.class)
#Null(groups = SecondGroup.class)
private String shortTitle;
then it is interpreted as
#Size(max = 50)
#NotNull(groups = DefaultGroup.class)
#Null(groups = SecondGroup.class)
#Column(length = 255, nullable = true)
private String shortTitle;
see more details here
Why does Hibernate Tools hbm2ddl generation not take into account Bean Validation annotations?
For Hibernate 5.2.7 (in my case) I've wrote a method to export schema that is based on packages scan like:
static void exportSchema(
DataSource dataSource,
Class<? extends Dialect> dialect,
String... packagesToScan) {
StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder()
.applySetting(DATASOURCE, dataSource)
.applySetting(DIALECT, dialect); // dialect could be omitted
MetadataSources metadataSources = new MetadataSources(registryBuilder.build());
PathMatchingResourcePatternResolver resourceLoader = new PathMatchingResourcePatternResolver();
new LocalSessionFactoryBuilder(null, resourceLoader, metadataSources)
.scanPackages(packagesToScan);
Metadata metadata = metadataSources.buildMetadata();
new SchemaExport()
.setFormat(true)
.create(EnumSet.of(STDOUT, DATABASE), metadata);
}

Reference to a Spring GenericBeanDefinition

I am trying to define my beans programmatically. I have 1 DAO bean, used by 2 other services beans. The DAO bean is injected as a constructor argument.
How can I get a reference to the DAO bean to build the service beans (analog to <bean ref="myDAO"/>) ?
My DAO is defined as (with DefaultListableBeanFactory beanFactory):
final GenericBeanDefinition myDAODefinition = new GenericBeanDefinition();
myDAODefinition.setBeanClassName("com.xxx.dao");
final BeanDefinitionHolder myDAOHolder = new BeanDefinitionHolder(myDAODefinition,"myDAO");
BeanDefinitionReaderUtils.registerBeanDefinition(myDAOHolder, beanFactory);
Then my services beans:
final GenericBeanDefinition srv1Definition = new GenericBeanDefinition();
srv1Definition.setBeanClassName("com.xxx.service1");
srv1Definition.setConstructorArgumentValues(new ConstructorArgumentValues() {
{
addGenericArgumentValue(*** ref to "myDAO" holder ***);
}
});
final BeanDefinitionHolder srv1Holder = new BeanDefinitionHolder(srv2Definition, "srv1");
and:
final GenericBeanDefinition srv2Definition = new GenericBeanDefinition();
srv2Definition.setBeanClassName("com.xxx.service2");
srv2Definition.setConstructorArgumentValues(new ConstructorArgumentValues() {
{
addGenericArgumentValue(*** ref to "myDAO" holder ***);
}
});
final BeanDefinitionHolder srv2Holder = new BeanDefinitionHolder(srv2Definition, "srv2");
How to reference "myDAO" Holder to inject it twice in other definitions ?
Note that I cannot use annotations.
Thanks in advance.
Found out, just use:
Object myDAORef = new RuntimeBeanReference("myDAO");
and inject it as the constructor argument.

Spring - jdbcTemplate

I'm just beginning with Spring framework. I'm also using DBCP pooling and i'm still not sure how to work right with jdbcTemplate.
It is best practice to reuse created/injected jdbcTemplate instance between multiple DAOs or it is right to create jdbcTemplate for each DAO ?
I'm currently using annotation approach:
public class FooDAO {
private JdbcTemplate jdbcTemplate;
#Autowired
public void setDatasource( DataSource dataSource ) {
this.jdbcTemplate = new JdbcTemplate( dataSource );
}
}
I'm aware about JdbcDaoSupport, but I don't know how to inject datasource, because method setDatasource is marked as final.
But still, I'm not sure if is best practice to reuse created jdbcTemplate or not.
Inject it in and share it. Don't call "new"; that takes control out of the hands of the Spring bean factory.
I'm aware about JdbcDaoSupport, but I don't know how to inject datasource, because method setDatasource is marked as final.
public class JdbcDaoSupportTest extends JdbcDaoSupport {
public void insert() {
this.getJdbcTemplate().execute("insert into tb_test1 values(1,'ycl','123')");
System.out.println("complete...");
}
}
Spring call set Method, don't care whether the method is final or not.
<bean id="jdbcDaoSupportTest" class="com.xxxxx.JdbcDaoSupportTest">
<property name="dataSource" ref="dataSource" />
</bean>
then in your JdbcDaoSupportTest, you can call this.getJdbcTemplate() to get JdbcTemplate do
any operator.
try {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
String sql = "select user.id as id,user.roll_no as createdId,user.name as name,user.type as company,role.role as year "
+ "from user_role join user on user.id=user_role.user_id "
+ "join role on role.id=user_role.role_id "
+ "where (user.status='ACTIVE' or user.status='ADMIN') AND user.username='" + userName + "'";
UserVo userDetails = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<UserVo>(UserVo.class));
or
Long company = jdbcTemplate.queryForObject(sql, Long.class);
or
List<UserVo> users = jdbcTemplate.query(sql, new BeanPropertyRowMapper<UserVo>(UserVo.class));
logger.info("Retrieve user details by username");
return userDetails;
} catch (Exception e) {
logger.error("error in getting UserDetails using UserName", e);
}

Resources