Injecting queries into DAOs via a spring config file - java

I'm looking at my project's DAO class which has native sql query in java class. there are different queries based on different condition. I'm planning to take out these query from java class. It can be something like this -
<bean name="hibernateRuleDao" class="com.xyz.dao.RuleDao">
<property name="ruleForSystemQuery">
<value>
select distinct rule from NormalRule as rule
inner join fetch rule.dimensions dimensions
where rule.system = :system and rule.status = :status
</value>
</property>
<property name="ruleAuditQuery">
<value>
select ra from RuleAudit ra where ra.rule.name =
:ruleName
</value>
</property>
</bean>
Is this the right approach ? Any other better approach to do this ?
Note: Using hibernate/jpa named query is not feasible in my use case.

If the purpose is to facilitate SQL modification without code recompilation, then yes this will do. You just need to inject RuleDao into your DAO classes.
However in my opinion SQL query modification should go through standard software lifecycle (design, implement, test, operate). So I'm happy with my SQL queries being hardcoded into DAO classes.

Related

Using native queries but maintaining database independence

With Spring JPA is there an easy way to use native queries but maintaining database independence, for example by using the query which fits best?
At the moment I do this by checking the currently set Dialect from the Environment and call the proper method of my Repository:
public Foo fetchFoo() {
if (POSTGRES_DIALECT.equals(env.getRequiredProperty("hibernate.dialect"))) {
return repo.postgresOptimizedGetFoo();
}
return repo.getFoo();
}
This works but I have the feeling that there is a better way or that I am missing something. Especially because (Spring) JPA allows it to use native queries quite easily but that breaks one of its big advantages: database independence.
As per my understanding, this can be achieved simply by using #Transactional(readOnly=false) and then instead of calling session.createQuery, one can use session.createSQLQuery, as provided in this example.
Your sql can be any of your native query.
Hope this works for you. :)
#Override
#Transactional(readOnly = false)
public Long getSeqVal() {
Session session = entityManager.unwrap(Session.class);
String sql = "SELECT nextval('seqName')";
Query query = session.createSQLQuery(sql);
BigInteger big = (BigInteger) query.list().get(0);
return big.longValue();
}
This is just an idea: I do not know whether it works or not:
My idea would be having subinterfaces, one normal Spring-Data-JPA-interface with all methods for one entiy (without native query hints). Than I would crate a subinterface for every database, that "override" the database specific native statements. (This intrface would be empty if there are no DB specific statements). Then I would try configure Spring-JPA with some profiles to load the right specific interface (for example by a class-name or package-name-pattern)
This seems like a way to complicated way to get queries to work.
If you really want to use optimized queries make it at least transparant for your code. I suggest using named queries and create an orm.xml per database (much like Spring Boot uses to load the schema.xml for a different database).
In your code you can simply do
public interface YourRepository extends JpaRepository<YourEntity, Long> {
List<YourEntity> yourQueryMethod();
}
This will look for a named query with the name YourEntity.yourQueryMethod. Now in your orm.xml add the named query (the default one and in another one the optimized one).
Then you need to configure your LocalContainerEntityManagerFactory to load the specific one needed. Assuming you have a property defining which database you use, lets name it database.type you could do something like the following
<bean class="LocalContainerEntityManagerFactoryBean">
<property name="mappingResources" value="classpath:META-INF/orm-${database.type}.xml" />
... other config ...
</bean>
This way you can keep your code clean of the if/then/else construct and apply where needed. Cleans your code nicely imho.

Select and Update hibernate caching table

I'm just implementing the hibernate query cache. I just want to know the behavior/working of hibernate cache concept if I do a manual update and hibernate update on the table which has been cached already.
Scenario:
Select cache Table A
Update Table A (manually or hibernate)
Select Table A again
The changes are reflected or I need to restart the server.
Below are my hibernate properties
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.DB2Dialect
hibernate.format_sql=true
hibernate.show_sql=false
hibernate.cache.use_second_level_cache=true
hibernate.cache.use_query_cache=true
hibernate.generate_statistics=true
org.hibernate.cache.ehcache.configurationResourceName=/ehcache.xml
hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
</value>
</property>
If you always update the TableA through Hibernate API, then the Query Cache might get invalidated.
With HQL, you are safe because Hibernate can extract the updated tables and invalidate the query cache regions that might get stale.
With native queries, all Query Cache regions are invalidated whenever you run a native SML statement. To restrict the affected Query Cache regions, you need to specify a Synchronization as follow:
session.createSQLQuery(
"update TableA set name = '\"'||name||'\"' "
)
.addSynchronizedEntityClass(TableA.class)
.executeUpdate()

Run "hibernate.hbm2ddl.auto = validate" in code; Hibernate schema validation

usually I would set
<property name="hibernate.hbm2ddl.auto" value="validate"/>
in the persistence.xml if I would like to check if my database is consistent with my annotated entities (Am I right?)
Now this validation would fail at application start up because there will be some migrations after, so I have to disable validation at this place.
But after my migrations I would like to run anything out of my code which compares that my database tables meet the annotated entities of my code!
The Validation looks for perfection you dont need. In example, the Range of java.sql.Date may differs from the range of the congrete Column type Date.
Anyway, try this after your startup and migrations:
AnnotationConfiguration conf = new AnnotationConfiguration();
conf.addClass(...);
conf.validateSchema(...);

Good way to generate SQL strings in java?

I'm not looking for a persistence layer like Hibernate, I just want to generate SQL-strings and they should be compatible with PreparedStatement. I've tried libraries such as Squiggle, but it only supports SELECT, I would also like to generate insert and updates. An ideal usage would be something like:
generateInsertOn("myTable").addValue("value1").addValue("value2").generate();
that would generate this string:
"INSERT INTO myTable (value1, value2) VALUES(?, ?)"
I know that there exists questions that are a lot like mine, such as this, but they don't quite ask the same thing as I do.
For arbitrary SQL, use jOOQ. jOOQ currently supports SELECT, INSERT, UPDATE, DELETE, TRUNCATE, and MERGE. You can create SQL like this:
// Since you're not executing the SQL, set connection to null
Connection connection = null;
Factory create = new MySQLFactory(connection);
String sql1 = create.select(A, B, C)
.from(MY_TABLE)
.where(A.equal(5))
.and(B.greaterThan(8))
.getSQL();
String sql2 = create.insertInto(MY_TABLE)
.values(A, 1)
.values(B, 2)
.getSQL();
String sql3 = create.update(MY_TABLE)
.set(A, 1)
.set(B, 2)
.where(C.greaterThan(5))
.getSQL();
The supported syntax is quite rich. You will also find support for clauses such as ON DUPLICATE KEY UPDATE, FOR UPDATE, LOCK IN SHARE MODE, etc.
For more details, see
http://www.jooq.org
(Disclaimer, I work for the company behind jOOQ)
You should definitively take a look at SQLBuilder. It allows simple, yet complete, SQL generation using a very fluent API.
Going out on a limb here, have you considered iBatis? It's a real down to earth query mapping framework (I hesitate to call it an ORM framework somehow). You have to create XML files like this one:
<mapper namespace="org.mybatis.jpetstore.persistence.ProductMapper">
<cache />
<select id="getProduct" parameterType="string" resultType="Product">
SELECT
PRODUCTID,
NAME,
DESCN as description,
CATEGORY as categoryId
FROM PRODUCT
WHERE PRODUCTID = #{productId}
</select>
</mapper>
which wires up a mapper like this one:
public interface ProductMapper {
Product getProduct(String productId);
}
Which allows you to access data from services like this:
#Autowired
private ProductMapper productMapper;
public Product getProduct(String productId) {
return productMapper.getProduct(productId);
}
Which you can wire up with Spring:
<!-- enable autowire -->
<context:annotation-config />
<!-- enable transaction demarcation with annotations -->
<tx:annotation-driven />
<!-- define the SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="typeAliasesPackage" value="org.mybatis.jpetstore.domain" />
</bean>
<!-- scan for mappers and let them be autowired -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="org.mybatis.jpetstore.persistence" />
</bean>
See also the full petstore example.
I'm not an uniquivocal fan of iBatis but it might fit your needs in this specific case.

Querying "extension tables" using Hibernate

I am having a querying issue in Hibernate. I have a table, 'test', with existing data. I have a requirement where I can not modify the schema of the test table, so I created another table, 'testExtension', whose primary key is a foreign key to the primary key of Test. Data in testExtension is a subset of the data in test. i.e. There will be less rows in 'testExtension' than in 'test'.
I have defined this relationship in a configuration file as follows:
<class name="Test" table="test">
<id name="testId" column="test_id">
<generator class="sequence">
<param name="sequence">test_id_seq</param>
</generator>
</id>
<property name="name"/>
<joined-subclass name="TestExtension" table="testExtension">
<key column="test_id"/>
<property name="summary" />
<property name="homepage"/>
</joined-subclass>
With this setup, I am able to create a TestExtension object in my Java program, populate it with data, 'save' it via Hibernate, and commit the transaction. And it correctly saves data in both Test and TestExtension.
My problem is occurring when I am trying to query data from these tables. Right now if I query for a particular test_id using the TestExtension.class to QBE, it will only return a row if that id exists in both Test and TestExtension. If I use the Test.class to QBE, it will return the row but I will not have access to any of the data stored in TestExtension.
My question is: how can I query these tables so that the results are based off a 'left outer join' of both Test and TestExtension? Any solution is appreciated, whether it's query by example, HQL, or something else (though preferably not raw SQL).
Thanks!
HQL is probably the easiest way to do this. Docs are here:
http://docs.jboss.org/hibernate/stable/core/reference/en/html/queryhql-joins.html
Sounds like what you might want to do is remap your relationships so that Test and TestExtension use a one-to-one relationship instead of inheritance. Then you can query for Test and TestExtension using a left outer join across the one-to-one.
If you use HQL to write a query for the Test class, it should do what you want. I assume QBE is effectively adding the class of your example entity as one of the query parameters.
So sth like:
from Test t where t.property = :value
should return either Test or TestExtension entities. Note that (at least with the versions of Hibernate I've used). In this case, Hibernate should immediately give you back the actual entities rather than a proxy too--- be aware that TestExtension entities can sometimes be returned as plain Test lazy-loading proxies.

Categories

Resources