How does Spring JPA Repository save() method handle auto_increment columns? - mysql

Say we input username: hello The entity below save the user info in User regU
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int user_id;
#Column(name = "username")
private String username;
The database already have 3 users with (auto_increment) id 1,2 and 3
Then we run the JPA save method:
URepo.save(regU)
Would the user normally get saved with id 4?
I tried test to this in my code, but when I run the save() method, literally nothing happens, hibernate doesn't show me the query it ran, no exception thrown, no changes in database.
My other queries print to console, but not save().
My JPA has these properties:
<property name="jpaProperties">
<props>
<prop key="hibernate.show_sql">true</prop>
<prop key="format_sql">true</prop>
<prop key="use_sql_comments">true</prop>
<prop key="hibernate.hbm2ddl.auto">validate</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
</props>
</property>
Edit 1:
My current code gives the new entity the id of 0, how would spring-data save an id of 0, and is it normal for the new entity to have id of 0 rather than the auto_increment value?

Related

Hibernate Connection Leak

i'm kinda new on web dev, i'm a trainee on a company since last year and i have the following problem:
I'm making a web app with JSF2.3 and Hibernate 5.4.2.Final and c3p0 5.4.2.Final. The thing is everytime i run and go for the login page, i need to check if there is an admin user already registered - i make a count on employee's table based on employee's code - and if there isn't any administrator, then i get a list of country states and render a form register menu.
So, i get the session from the sessionfactory.opensession() in mine HibernateUtil.class, do the count and clear/close the session like the snipet:
public Long retornaLong(String query) throws Exception{
Session session = new HibernateUtil().getSession();
try {
return (Long) session.createQuery(query).getSingleResult();
}finally {
session.clear();
session.close();
}
}
then i get the country states list from
#SuppressWarnings("unchecked")
public List<T> retornaList(String query) throws Exception{
Session session = new HibernateUtil().getSession();
try {
return (List<T>) session.createQuery(query).getResultList();
}finally {
session.clear();
session.close();
}
}
but if i keep refreshing the page (#viewscoped), like 15+ times, eventually i'll get too many connection exception, this doesn't happen if i use one session for both queries. I think there's no enough time for the session to close, causing a connection leak. I want to use one session for each query, can someone help me. Thanks a lot.
My hibernate.cfg.xml
<hibernate-configuration>
<!-- a SessionFactory instance listed as /jndi/name -->
<session-factory>
<!-- properties -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/vetsnpets?useTimezone=true&serverTimezone=UTC</property>
<property name="hibernate.connection.username">vetsNpets</property>
<property name="hibernate.connection.password">123</property>
<property name="hiberante.show_sql">false</property>
<property name="hiberante.format_sql">false</property>
<property name="hbm2ddl.auto">validate</property>
<property name="current_session_context_class">thread</property>
<!-- C3P0 -->
<property name="hibernate.c3p0.initialPoolSize">3</property>
<property name="hibernate.c3p0.minPoolSize">3</property>
<property name="hibernate.c3p0.maxPoolSize">20</property>
<property name="hibernate.c3p0.maxStatements">100</property>
<property name="hibernate.c3p0.maxStatementsPerConnection">5</property>
<property name="hibernate.c3p0.maxIdleTime">2700</property>
<property name="hibernate.c3p0.maxIdleTimeExcessConnections">600</property>
<property name="hibernate.c3p0.acquireIncrement">1</property>

Converting MySQL to H2

I’m working on a project following this code :
Link to download of code: https://bitbucket.org/vrto/spring-tutorial/get/a66534cc7033.zip
Now what I really want, instead of MySQL, is to have an embedded database running HSQL or H2. So I’ve working on my own project trying to implement such a system.
In the tutorial code, he creates a database. And then h2 + hibernates creates the future tables for him – so it would be create if I could do this without having to have an sql schema or anything to set it up.
So I’ve gotten rid of mySql maven dependencies and am working on replacing the persistence-beans.xml
Now I have to replace my dataSource with a relevant h2 or hsql version.
So this is what I’ve gotten.
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name ="driverClassName" value = "org.h2.driver"/>
<property name = "url" value ="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1" />
<property name = "username" value = "sa" />
<property name = "password" value = "" />
</bean>
// I also tried this (but again, having a schema with his code is tricky I’ve found
<jdbc:embedded-database id="dataSource" type="H2">
<jdbc:script location="classpath:schema.sql"/>
<jdbc:script location="classpath:test-data.sql"/>
</jdbc:embedded-database>
But it fails upon running HibernateConfigurationTest.Java (and in extension – all the others)
Any help would be greatly appreciated.
I've managed to get this test work with my schema
#ContextConfiguration(locations = "/persistence-beans.xml")
public class HibernateConfigurationTest extends AbstractJUnit4SpringContextTests {
#Autowired
private SessionFactory sessionFactory;
#Test
public void testHibernateConfiguration() {
// Spring IOC container instantiated and prepared sessionFactory
assertNotNull (sessionFactory);
}
}
the rest tests are in this link : http://vrtoonjava.wordpress.com/2012/06/17/part-3-dao-and-service-layer/

insert into table using hibernate #Transactional

I am using #Transactional annotation to test inserting some data into one of the tables through a Spring application. My test succeeds, but I do not see any data being inserted into the table.
Here are the relevant code snippets:
MyTest:
#TransactionConfiguration(transactionManager="MyTxManager")
#Transactional
public class MyTest {
#Autowired
private DataProvider provider;
#Test
#Transactional
void testInsert() {
Order purchaseOrder = new Order("ID1", "LER", "VDR1", 0, );
provider.addRow(purchaseOrder);
}
}
DataProvider:
public class DataProvider extends DatabaseProvider {
// some stuff...
#Transactional
public void insertRow(Order purchaseOrder) {
/*
* SessionFactory is got through autowiring
* and is working perfectly fine.
*/
Session session = sessionFactory.getCurrentSession();
// This should save the row into the table - which it doesn't :(
session.save(purchaseOrder);
}
}
information-providers.xml
<bean id="DataProvider" class="com.util.DataProvider">
<property name="sessionFactory" ref="MySessionFactory" />
</bean>
hibernate.xml containing the configuration of session factory
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"
parent="AbstractSessionFactory" depends-on="EnvironmentHelper">
<property name="hibernateProperties">
<props>
<prop key="hibernate.connection.autocommit">true</prop>
<prop key="hibernate.connection.provider_class">com.hibernate.ConnectionPool</prop>
<prop key="hibernate.connection.driver_class">${driverClassName}</prop>
<prop key="hibernate.connection.url">${databaseURL}</prop>
<prop key="hibernate.connection.username">${databaseUsername}</prop>
<prop key="hibernate.connection.password">${databasePassword}</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.default_schema">${databaseDefaultSchema}</prop>
</props>
</property>
</bean>
<!-- Use Spring transactions for Hibernate -->
<tx:annotation-driven transaction-manager="MyTxManager" mode='proxy' proxy-target-class='true'/>
<bean id="MyTxManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="MySessionFactory" />
</bean>
</beans>
I think the problem in rolling back the transactions. See here defaultRollback method.
Try like this:
#TransactionConfiguration(transactionManager="MyTxManager", defaultRollback=false)
Your problem is that MyProvider myProviderInstance = new MyProvider(); the myProviderInstance isn't maintained by Spring container, you just new it, so the Spring can't do anything about it, definitely the transaction doesn't work. You should config the bean in Spring applicationcontext.xml and load it with ApplicationtContext, you can find dozens of sample after google it. And since you use Mysql you should make sure that you use innerDB mode or the transaction isn't supported by mysql.
add the line <tx:annotation-driven/> to your spring configuration

Connecting to a MySQL database from a Spring project

I have been trying to access MySQL routines from my Spring project using SimpleJdbcDaoSupport.
I have a class called AdminSimpleMessageManager, which implements the interface AdminMessageManager.
AdminSimpleMessageManager has an instance of the class AdminSimpleJdbcMessageDao, which implements the interface AdminMessageDao.
AdminSimpleJdbcMessageDao has the following method:
public class AdminSimpleJdbcMessageDao extends SimpleJdbcDaoSupport implements AdminMessageDao {
public int addMessage(String from, String message) {
return getJdbcTemplate().queryForInt("call insert_contact_message(?, ?)", from, message);
}
}
I have included the following in my application context:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/OctagonDB"/>
</bean>
<bean id="adminMessageManager" class="Managers.AdminSimpleMessageManager">
<property name="adminMessageDao" ref="adminMessageDao"/>
</bean>
<bean id="adminMessageDao" class="Managers.dao.AdminSimpleJdbcMessageDao">
<property name="dataSource" ref="dataSource"/>
</bean>
but I feel there are a few important lines missing. I get the error
SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/NewWebsite] threw exception [Request processing failed; nested exception is org.springframework.dao.TransientDataAccessResourceException: PreparedStatementCallback; SQL [call insert_contact_message(?, ?)]; ResultSet is from UPDATE. No Data.; nested exception is java.sql.SQLException: ResultSet is from UPDATE. No Data.] with root cause
java.sql.SQLException: ResultSet is from UPDATE. No Data.
I am wondering if the SQL routine needs to return some confirmation? Or maybe I am accessing the DB with the wrong information, is there a way of determining whether it even connected?
EDIT:
insert_contact_message looks like this:
CREATE DEFINER=`root`#`localhost` PROCEDURE `insert_contact_message`(
_author VARCHAR(45),
_message MEDIUMTEXT
)
BEGIN
INSERT INTO contact_messages (`author`, `message`, `date_sent`) VALUES (_author, _message, NOW());
END
You're using queryForInt, but insert_contact_message doesn't return a result. I haven't used JdbcTemplate before, but it looks like you might want to use execute that doesn't expect a result set.
Another option is to change from using a procedure to a function.
CREATE DEFINER=`root`#`localhost` FUNCTION `insert_contact_message`(
_author VARCHAR(45),
_message MEDIUMTEXT
)
BEGIN
INSERT INTO contact_messages (`author`, `message`, `date_sent`) VALUES (_author, _message, NOW());
RETURN 1;
END

Hibernate list using cache? -Not updating entity attribute

I have an application that uses hibernate.
I did the following:
Used List to list some entities on database
Logged in my Mysql Database manualy and updated a field in some
entities
Used List again in hibernate doing an identical query as 1
The entity that hibernate listed was not updated.
If I close and open the application. it then shows the entity updated correctly.
Is hibernate using some kind of cache by default?
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/XXX</property>
<property name="hibernate.connection.username">XXXXXXXXXX</property>
<property name="hibernate.connection.password">XXXXXXXXXX</property>
<property name="show_sql">true</property>
Code that lists the entity:
Session s = HibernateUtil.getSession();
Criteria c = s.createCriteria(Solicitacao.class, "s");
//Add some Restrictions here
List<Solicitacao> ls = c.list();
s.close();
My Session factory:
public class HibernateUtil {
private static SessionFactory sessionFactory = null;
static {
// Configurações iniciais de caminho dos diretórios e arquivos
URL url = HibernateUtil.class.getProtectionDomain().getCodeSource().getLocation();
File myFile = null;
try {
myFile = new File(url.toURI());
} catch (Exception ex) {
}
File dir = myFile.getParentFile();
File xml = new File(dir, "hibernate.cfg.xml");
/*
* sessionFactory = new AnnotationConfiguration() .configure("br/com/netradiobrasil/pcp/" +
* "hibernate/hibernate.cfg.xml") .buildSessionFactory();
*/
sessionFactory = new AnnotationConfiguration().configure(xml).buildSessionFactory();
}
public static Session getSession() {
return sessionFactory.openSession();
}
}
I tryed to add those lines in my hibernate.cfg.xml
<property name="hibernate.cache.use_query_cache">false</property>
<property name="hibernate.cache.use_second_level_cache">false</property>
<property name="hibernate.cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
Also tryed to use: session.setCacheMode(CacheMode.IGNORE)
but still didnt solve my problem
Let me guess
After executing this
Session s = HibernateUtil.getSession();
Criteria c = s.createCriteria(Solicitacao.class, "s");
//Add some Restrictions here
List<Solicitacao> ls = c.list();
You changed entries in database manually and then reran the query ? If yes then can you close the session and then rerun your code ?
Adding those lines in my hibernate.cfg.xml - that enables c3p0 fixed my problem
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_size">40</property>
<property name="hibernate.c3p0.timeout">300</property>
<property name="hibernate.c3p0.max_statements">50</property>
<property name="hibernate.c3p0.idle_test_period">100</property>