When I use JPA delete, I get an error. I check the log and find an update SQL, I don't know why I execute the deleting, but it prints update SQL
java 1.8, spring-data-jpa-2.1.8
the source code:
cardApplyRepository.delete(CardApply.builder().activityId(23443L).build());
the log:
2019-07-15 13:09:20.478 [main] INFO o.s.t.w.s.TestDispatcherServlet [initServletBean:546] - Completed initialization in 19 ms
Hibernate:
insert
into
t_card_apply
(activity_id, activity_name, app_id, card_base_required_id, card_id, mass_msg_id, seller_id)
values
(?, ?, ?, ?, ?, ?, ?)
2019-07-15 13:09:20.573 [main] WARN o.h.e.j.s.SqlExceptionHelper [logExceptions:137] - SQL Error: 1048, SQLState: 23000
2019-07-15 13:09:20.574 [main] ERROR o.h.e.j.s.SqlExceptionHelper [logExceptions:142] - Column 'card_base_required_id' cannot be null
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:296)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:253)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:527)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:138)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy206.delete(Unknown Source)
at com.geek.icem.wechat.service.impl.WxCardServiceImplTest.deleteCard(WxCardServiceImplTest.java:34)
When you pass an Entity to the delete method it should be managed at this point.
For example by using the findById method and passing the result to delete.
You are passing a non-managed entity as you build it on the fly.
So either fetch one first or use the deleteById method instead.
We might not inspect your issue in detail unless you provide the code of CardApply and CardApplyRepository if you are using a custom repository implementation.
What I can get is, you want to delete an entity by id, so, I suggest you that just use the deleteById method of Spring data's CrudRepository like below:
cardApplyRepository.deleteById(23443L);
Hope this helps. Good luck!
Related
I'm refactoring a code from a project and during my lunch I started looking at some error logs from the application running the old code. It's somehow related to the EntityManager#flush method (this project is using Hibernate as the persistence framework).
There's a process that select some X rows (up to 10) from a process and lock them by using for update -- #Lock(LockModeType.PESSIMISTIC_WRITE). This is within a transaction boundary and it uses Spring Data JPA Repositories and Spring Transaction Management (#Transactional).
I saw the following code (just a representation, since the actual code is huge):
#Transactional
public void method() {
// uses #Lock(LockModeType.PESSIMISTIC_WRITE)
List<Foo> entities = fooRepository.selectForUpdate();
// iterates all entities, do some work and update them
for (Foo foo: entities) {
foo.setX(321);
}
// save the list of entities
fooRepository.saveAll(foo);
// flush() is causing LockAcquisitionException
fooRepository.flush();
}
By looking at the logs, the line fooRepository.flush() is causing a LockAcquisitionException. This is really strange to me and I've never saw this before. If the rows were already selected successfully, how do this exception occurs while flushing?
Funny enough, this only happens during high throughputs periods of the day.
A snippet from the StackTrace:
org.springframework.dao.CannotAcquireLockException: could not execute statement; SQL [n/a]; nested exception is org.hibernate.exception.LockAcquisitionException: could not execute statement
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:287)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:253)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:527)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:144)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$ExposeRepositoryInvocationInterceptor.invoke(CrudMethodMetadataPostProcessor.java:364)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy150.flush(Unknown Source)
at xxx.xxx.xxx.xxx.MyClass.method(MyClass.java:764)
....
As per the last line of this snippet, you see that the error occurs on line 764, which is exactly where the flush happens.
Why is this happening?
Without the full stack trace and logs it is impossible to help you. The exception usually indicates a deadlock or lock timeout, so maybe you are flushing something that isn't locked yet. When flushing, MySQL tries to lock the rows in some order and if some other TX acquires locks in a different order, you see a deadlock like this.
I would like JPA application to validate schema during start. For this reason I added the following property to persistence.xml:
<property name="hibernate.hbm2ddl.auto" value="validate"/>
However hibernate fails to validate schema:
...
Caused by: org.hibernate.exception.SQLGrammarException: Error accessing table metadata
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:106)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)
at org.hibernate.tool.schema.extract.internal.InformationExtractorJdbcDatabaseMetaDataImpl.convertSQLException(InformationExtractorJdbcDatabaseMetaDataImpl.java:98)
at org.hibernate.tool.schema.extract.internal.InformationExtractorJdbcDatabaseMetaDataImpl.getTables(InformationExtractorJdbcDatabaseMetaDataImpl.java:341)
at org.hibernate.tool.schema.extract.internal.DatabaseInformationImpl.getTablesInformation(DatabaseInformationImpl.java:120)
at org.hibernate.tool.schema.internal.GroupedSchemaValidatorImpl.validateTables(GroupedSchemaValidatorImpl.java:39)
at org.hibernate.tool.schema.internal.AbstractSchemaValidator.performValidation(AbstractSchemaValidator.java:89)
at org.hibernate.tool.schema.internal.AbstractSchemaValidator.doValidation(AbstractSchemaValidator.java:68)
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:191)
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:72)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:309)
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:462)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:938)
... 41 more
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: USE statement is not supported to switch between databases. Use a new connection to connect to a different database.
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:254)
at com.microsoft.sqlserver.jdbc.TDSTokenHandler.onEOF(tdsparser.java:258)
at com.microsoft.sqlserver.jdbc.TDSParser.parse(tdsparser.java:104)
at com.microsoft.sqlserver.jdbc.TDSParser.parse(tdsparser.java:26)
at com.microsoft.sqlserver.jdbc.SQLServerConnection$1ConnectionCommand.doExecute(SQLServerConnection.java:2907)
at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:7240)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:2869)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectionCommand(SQLServerConnection.java:2912)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.setCatalog(SQLServerConnection.java:3227)
at com.microsoft.sqlserver.jdbc.SQLServerDatabaseMetaData.switchCatalogs(SQLServerDatabaseMetaData.java:342)
at com.microsoft.sqlserver.jdbc.SQLServerDatabaseMetaData.getResultSetFromStoredProc(SQLServerDatabaseMetaData.java:296)
at com.microsoft.sqlserver.jdbc.SQLServerDatabaseMetaData.getResultSetWithProvidedColumnNames(SQLServerDatabaseMetaData.java:318)
at com.microsoft.sqlserver.jdbc.SQLServerDatabaseMetaData.getTables(SQLServerDatabaseMetaData.java:502)
at org.apache.tomcat.dbcp.dbcp.DelegatingDatabaseMetaData.getTables(DelegatingDatabaseMetaData.java:604)
at org.hibernate.tool.schema.extract.internal.InformationExtractorJdbcDatabaseMetaDataImpl.getTables(InformationExtractorJdbcDatabaseMetaDataImpl.java:329)
... 50 more
Is there any workaround except disable validation?
It's seems to there is syantx error in SQL file. Some time the SQL might get different from database to database, and the other another database not compitable for the sql syntax you using.
I am currently working on a Java application that uses Spring Social to communicate with Twitter. The application uses Spring Data (JPA) to manage users locally.
When I authorize access on Twitter and Twitter makes a request to the OAuth1 callback URL, my application chokes and I see the following in my log file (I've shortened the stacktrace):
ERROR 2013-08-18 16:05:09,511 http-bio-8080-exec-44] org.springframework.transaction.interceptor.TransactionInterceptor [TransactionAspectSupport.completeTransactionAfterThrowing
(): "Application exception overridden by rollback exception"]
org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; uncategorized SQLException for SQL [insert into UserConnection (userId, providerId, providerUserId, ra
nk, displayName, profileUrl, imageUrl, accessToken, secret, refreshToken, expireTime) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)]; SQL state [null]; error code [0]; You can't operate
on a closed Connection!!!; nested exception is java.sql.SQLException: You can't operate on a closed Connection!!!
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:83)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:603)
...
Caused by: java.sql.SQLException: You can't operate on a closed Connection!!!
at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:118)
at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:77)
at com.mchange.v2.c3p0.impl.NewProxyConnection.prepareStatement(NewProxyConnection.java:171)
at org.springframework.jdbc.core.JdbcTemplate$SimplePreparedStatementCreator.createPreparedStatement(JdbcTemplate.java:1438)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:581)
... 94 more
Caused by: java.lang.NullPointerException
at com.mchange.v2.c3p0.impl.NewProxyConnection.prepareStatement(NewProxyConnection.java:135)
... 96 more
[WARN 2013-08-18 16:05:09,513 http-bio-8080-exec-44] org.springframework.social.connect.web.ConnectController [ConnectController.oauth1Callback(): "Exception while handling OAuth1 callback (Could not roll back JPA transaction; nested exception is javax.persistence.PersistenceException: unexpected error when rollbacking). Redirecting to twitter connection status page."]
After some research I believe I am essentially seeing the issue described here:
https://jira.springsource.org/browse/SOCIAL-384
For some reason the fact that Spring Social core uses a JdbcUsersConnectionRepository does not play nice with my JPA set up. I understand that a plugin is available; however I decided to experiment with the datasource configurations and created two essentially identical datasource bean configurations (with different names) and tied one to Spring Social and the other to my entity manager configuration.
With this setup the above error goes away and I am able to see my Twitter user connection get persisted to the database. My question is: is doing something like this a valid solution? What are some other scenarios that would require duplicate datasources? On the flip side - what are possible repercussions for using such a configuration?
Downside of this solution is that you need to reduce maximum capacity of connection pool.
Example: imagine that you have a connection pool with max 30 connections in it. Now you want to add another datasource for Spring Social. I suppose that each your user will use 2 datasources simultaneously. So you need 2 connection pools with max 15 connections in each. Now it will be much easier to hit the limit.
I'm getting below error when calling stored procedure XXXX written in Mainframe DB2. In this stored procedure, we have 'GRAPHIC' & 'LONGGRAPHIC' parameter for which I'm passing "java.sql.CHAR" and "java.sql.VARCHAR" type parameter.
INFO: SQLErrorCodes loaded: [DB2, Derby, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase]
Exception while executing Test Case
org.springframework.jdbc.BadSqlGrammarException: CallableStatementCallback; bad SQL grammar [{call SYSPROC.XXXX(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)}]; nested exception is com.ibm.db2.jcc.c.SqlException: DB2 SQL error: SQLCODE: -444, SQLSTATE: 42724, SQLERRMC: XXXX
Caused by: com.ibm.db2.jcc.c.SqlException: DB2 SQL error: SQLCODE: -444, SQLSTATE: 42724, SQLERRMC: XXXX
at com.ibm.db2.jcc.c.tf.d(tf.java:1396)
at com.ibm.db2.jcc.b.jb.l(jb.java:367)
at com.ibm.db2.jcc.b.jb.e(jb.java:92)
at com.ibm.db2.jcc.b.w.e(w.java:72)
at com.ibm.db2.jcc.b.cc.h(cc.java:203)
at com.ibm.db2.jcc.c.tf.q(tf.java:1363)
at com.ibm.db2.jcc.c.uf.d(uf.java:2388)
at com.ibm.db2.jcc.c.vf.Z(vf.java:159)
at com.ibm.db2.jcc.c.vf.execute(vf.java:142)
at org.springframework.jdbc.core.JdbcTemplate$5.doInCallableStatement(JdbcTemplate.java:906)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:872)
at org.springframework.jdbc.core.JdbcTemplate.call(JdbcTemplate.java:904)
at org.springframework.jdbc.object.StoredProcedure.execute(StoredProcedure.java:113)
at com.cst.test.common.SPCall.execute(SPCall.java:73)
at com.cst.test.daoLayer.SPTest.testLogic(SPTest.java:71)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:79)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:618)
at org.junit.internal.runners.TestMethodRunner.executeMethodBody(TestMethodRunner.java:99)
at org.junit.internal.runners.TestMethodRunner.runUnprotected(TestMethodRunner.java:81)
at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34)
at org.junit.internal.runners.TestMethodRunner.runMethod(TestMethodRunner.java:75)
at org.junit.internal.runners.TestMethodRunner.run(TestMethodRunner.java:45)
at org.junit.internal.runners.TestClassMethodsRunner.invokeTestMethod(TestClassMethodsRunner.java:66)
at org.junit.internal.runners.TestClassMethodsRunner.run(TestClassMethodsRunner.java:35)
at org.junit.internal.runners.TestClassRunner$1.runUnprotected(TestClassRunner.java:42)
at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34)
at org.junit.internal.runners.TestClassRunner.run(TestClassRunner.java:52)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:45)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Failed Test Case Count : 0
SQL code -444 means that the external program called from the stored procedure is not found. Either the name is incorrect, or the program is not linked properly.
More info here: http://pic.dhe.ibm.com/infocenter/dzichelp/v2r2/topic/com.ibm.db2z9.doc.codes/src/tpc/n444.htm
I am using JdbcTemplate.queryForInt to insert a Row into the DB, and then get the ID back.
The Query is "INSERT INTO metadocs(NAME) values (?) RETURNING METADOCID". If I run the statement in Flamerobin, it works fine.
However, if I run it from Java, I get the following error:
org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; uncategorized SQLException for SQL [INSERT INTO metadocs(NAME) values (?) RETURNING METADOCID]; SQL state [HY000]; error code [335544364]; GDS Exception. 335544364. request synchronization error; nested exception is org.firebirdsql.jdbc.FBSQLException: GDS Exception. 335544364. request synchronization error
Caused by: org.firebirdsql.jdbc.FBSQLException: GDS Exception. 335544364. request synchronization error
Does anyone have an idea what this could be caused by?
Unlike Oracle, I'm not sure that the Jaybird JDBC driver supports the RETURNING syntax. Alternatively, you might look at the getGeneratedKeys() method , discussed here.