I've done a program where I have to retrieve the data from a table in MS SQL. I'm using Hibernate where AbtDebtbyCAN is an Entity class. The connection so far is fine but the only problem I'm facing is printing out data from MS SQL using Annotation Mapping. Debt is the name of the table(the name of the table is in lower case) which is to be mapped with. Below here is the result I want to print it out using Hibernate. Can anybody help me on how to achieve the fetching of data?
debt
id can bdrl_debt excess_ta_debt posting_ref debt_settlement_id debt_settlement_at debt_business_date
11425 1099112400000003 0 200 501728 137 2020-10-13 10:51:50.000 2020-10-13
AbtDebtbyCAN
#Data
#Entity
#Table(name = "debt")
public class AbtDebtbbyCAN implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int debt_id;
#Column(name = "can")
private int debt_can;
#Column(name = "bdrl_debt")
private int bdrl_debt;
#Column(name = "excess_ta_debt")
private int excess_ta_debt;
#Column(name = "posting_ref")
private int posting_ref;
#Column(name = "debt_settlement_id")
private int debt_settlement_id;
#Column(name = "debt_settlement_at")
private DateTime debt_settlement_at;
#Column(name = "debt_business_date")
private Date debt_business_date;
}
AbtCANMapperTest
public class AbtCANMapperTest {
public static void main(String args[]) {
StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().configure("hibernate.cfg.xml").build();
Metadata meta = new MetadataSources(ssr).getMetadataBuilder().build();
SessionFactory factory = meta.getSessionFactoryBuilder().build();
Session session = factory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
List abtdebt = session.createQuery("FROM AbtDebtbbyCAN WHERE debt_can=1099112400000003").getResultList();
for (Iterator iterator = abtdebt.iterator(); iterator.hasNext(); ) {
AbtDebtbbyCAN abtcan = (AbtDebtbbyCAN) iterator.next();
System.out.print("debt id: " + abtcan.getDebt_id());
System.out.print("debt can: " + abtcan.getDebt_can());
System.out.print("bdrl debt: " + abtcan.getBdrl_debt());
System.out.print("excess debt: " + abtcan.getExcess_ta_debt());
System.out.print("posting ref: " + abtcan.getPosting_ref());
System.out.print("debt settlement id: " + abtcan.getDebt_settlement_id());
System.out.print("debt settlement at: " + abtcan.getDebt_settlement_at());
System.out.println("debt business date: " + abtcan.getDebt_business_date());
}
tx.commit();
} catch (HibernateException e) {
if (tx != null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
}
Error StackTrace
Exception in thread "main" javax.persistence.PersistenceException: org.hibernate.type.SerializationException: could not deserialize
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154)
at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1542)
at org.hibernate.query.Query.getResultList(Query.java:165)
at AbtMainTestControl.AbtTestObj.AbtCANMapperTest.main(AbtCANMapperTest.java:36)
Caused by: org.hibernate.type.SerializationException: could not deserialize
at org.hibernate.internal.util.SerializationHelper.doDeserialize(SerializationHelper.java:243)
at org.hibernate.internal.util.SerializationHelper.deserialize(SerializationHelper.java:287)
at org.hibernate.type.descriptor.java.SerializableTypeDescriptor.fromBytes(SerializableTypeDescriptor.java:138)
at org.hibernate.type.descriptor.java.SerializableTypeDescriptor.wrap(SerializableTypeDescriptor.java:113)
at org.hibernate.type.descriptor.java.SerializableTypeDescriptor.wrap(SerializableTypeDescriptor.java:29)
at org.hibernate.type.descriptor.sql.VarbinaryTypeDescriptor$2.doExtract(VarbinaryTypeDescriptor.java:60)
at org.hibernate.type.descriptor.sql.BasicExtractor.extract(BasicExtractor.java:47)
at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:257)
at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:253)
at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:243)
at org.hibernate.type.AbstractStandardBasicType.hydrate(AbstractStandardBasicType.java:329)
at org.hibernate.persister.entity.AbstractEntityPersister.hydrate(AbstractEntityPersister.java:3088)
at org.hibernate.loader.Loader.loadFromResultSet(Loader.java:1907)
at org.hibernate.loader.Loader.hydrateEntityState(Loader.java:1835)
at org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:1808)
at org.hibernate.loader.Loader.getRow(Loader.java:1660)
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:745)
at org.hibernate.loader.Loader.getRowsFromResultSet(Loader.java:1044)
at org.hibernate.loader.Loader.processResultSet(Loader.java:995)
at org.hibernate.loader.Loader.doQuery(Loader.java:964)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:350)
at org.hibernate.loader.Loader.doList(Loader.java:2887)
at org.hibernate.loader.Loader.doList(Loader.java:2869)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2701)
at org.hibernate.loader.Loader.list(Loader.java:2696)
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:506)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:400)
at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:219)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1415)
at org.hibernate.query.internal.AbstractProducedQuery.doList(AbstractProducedQuery.java:1565)
at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1533)
... 2 more
Caused by: java.io.StreamCorruptedException: invalid stream header: 0000AC53
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:899)
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:357)
at org.hibernate.internal.util.SerializationHelper$CustomObjectInputStream.<init>(SerializationHelper.java:309)
at org.hibernate.internal.util.SerializationHelper$CustomObjectInputStream.<init>(SerializationHelper.java:299)
at org.hibernate.internal.util.SerializationHelper.doDeserialize(SerializationHelper.java:218)
... 32 more
Caused by: org.hibernate.type.SerializationException: could not deserialize
> Task :AbtCANMapperTest.main() FAILED
Caused by: java.io.StreamCorruptedException: invalid stream header: 0000AC53
Execution failed for task ':AbtCANMapperTest.main()'.
> Process 'command 'C:/Program Files/Java/jdk1.8.0_241/bin/java.exe'' finished with non-zero exit value 1
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
Not sure what types you are exactly using here, but at least DateTime is not a standard type that is supported by Hibernate. If Hibernate does not know about a type, it tries to flush the value in its serialized form as blob/byte[]. If you would use java.sql.Timestamp, java.util.Calendar or any other type that is supported by Hibernate out of the box, this should work properly.
Related
I am not asking the question that is already asked here
Failed to convert from type [java.lang.Object[]] to type
My entity look like this :
#Entity
public class DuplicateManagerMetricsRelTagEntity {
#Id
#Column(name = "sn")
String sn;
#Column(name = "clientid")
String clientid;
#Column(name = "ticket_count")
String ticket_count;
public DuplicateManagerMetricsRelTagEntity(String sn, String clientid, String ticket_count) {
this.sn = sn;
this.clientid = clientid;
this.ticket_count = ticket_count;
}
public DuplicateManagerMetricsRelTagEntity() {
}
My controller look like this :
#RequestMapping("/qbr/duplicatemanager/{clientid}/{appid}/{releasetag}/")
#CrossOrigin
public List<DuplicateManagerMetricsRelTagEntity> getAllDuplicateManagerFromReleaseTag(#PathVariable String clientid, #PathVariable String[] appid, #PathVariable String releasetag) {
logger.info("Returing all duplicate managers of client {} appId {} from release tag {} ", clientid, appid, releasetag);
System.out.println("data in controller : " + clientid + " " + appid + " " + releasetag);
return duplicateManagerMetricsService.getAllDuplicateManagerFromReleaseTag(clientid, appid, releasetag);
}
My service look like this :
public List<DuplicateManagerMetricsRelTagEntity> getAllDuplicateManagerFromReleaseTag(String clientid, String[] appid, String releasetag) {
try {
System.out.println("data in service : "+ clientid + " " + appid + " " + releasetag);
return duplicateManagerMetricsRepository.getAllDuplicateManagerfromReleaseTag(clientid, appid, releasetag);
} catch (Exception e) {
logger.error(e);
return new ArrayList<>();
}
}
My Repository look like this :
#Query(value = "select a.sn, a.clientid, a.ticket_count from dbtable as a where a.clientid = ?1 AND a.appid in (?2) AND a.releasetag=?3", nativeQuery = true)
List<DuplicateManagerMetricsRelTagEntity> getAllDuplicateManagerfromReleaseTag(String clientid, String[] appid, String releasetag);
since i am not getting appid data, i was supposed to get[657-001] but it is printing its object and the error i am getting is :
DuplicateManagerMetricsController - Returing all duplicate managers of client 657 appId [657-001] from release tag WIL657.2021.05-001
data in controller : 657 [Ljava.lang.String;#63108943 WIL657.2021.05-001
data in service : 657 [Ljava.lang.String;#63108943 WIL657.2021.05-001
2022-09-02 05:08:54 DEBUG org.hibernate.SQL - select a.sn, a.clientid, a.ticket_count from dbtable as a where a.clientid = ? AND a.appid in (?) AND a.releasetag=?
2022-09-02 05:08:54 WARN o.h.e.jdbc.spi.SqlExceptionHelper - SQL Error: 933, SQLState: 42000
2022-09-02 05:08:54 ERROR o.h.e.jdbc.spi.SqlExceptionHelper - ORA-00933: SQL command not properly ended
[ERROR] 2022-09-02 05:08:54.566 [http-nio-8080-exec-2] DuplicateManagerMetricsService - org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet
This is because you are extracting fields (a.sn, a.clientid, a.ticket_count) which is not a DuplicateManagerMetricsRelTagEntity type. So since you have not asked hibernate to extract the complete object but a few fields(does not matter if your fields are exactly same as the fields in the object) - so hibernate extracts it as Object[] and then is trying to map to DuplicateManagerMetricsRelTagEntity and hence the issue.
You can use: JPA Projection/DTO
In your case you can use JPQL and :
"select a from DuplicateManagerMetricsRelTagEntity a where a.clientid = ?1 AND a.appid in (?2) AND a.releasetag=?3"
Or for native queries you an try:
select * from table_name where conditions;
NOTE: It has been long since I used hibernate or jpa. So the queries might be not completely accurate. Please do check up on the proper syntax. Main idea is to let you know how hibernate understands and tries to map the type. Since you have a,b,c -> Object[] is extracted and cannot be mapped to your entity.
I am using hibernate mapping one to many to complete my task. But when I ran the project, it ran into a problem: "Data truncation: Data too long for column 'tinhTrang' at row 1".
I can't get the point why I got this. I searched but I couldn't find any problem with boolean like me. Please help me. Thank everyone
.package com.javapoint;
import javax.persistence.*;
#Entity
#Table(name="DH")
public class DonHang {
#Id
#GeneratedValue(strategy=GenerationType.TABLE)
private int soDH;
private int maKH;
private double triGia;
#Column(nullable = false, columnDefinition = "TINYINT(4)")
private boolean tinhTrang;
public int getsoDH()
{
return soDH;
}
public void setsoDH(int soDH)
{
this.soDH = soDH;
}
public int getmaKH()
{
return maKH;
}
public void setmaKH(int maKH)
{
this.maKH = maKH;
}
public double gettriGia()
{
return triGia;
}
public void settriGia(double triGia)
{
this.triGia = triGia;
}
public boolean gettinhTrang()
{
return tinhTrang;
}
public void settinhTrang(boolean tinhTrang)
{
this.tinhTrang = tinhTrang;
}
}
Here is the error message:
Caused by: org.hibernate.exception.DataException: could not execute statement
at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:52)
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.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:178)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3171)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3686)
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:90)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:478)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:356)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1454)
... 9 more
Caused by: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Data too long for column 'tinhTrang' at row 1
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:104)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:974)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1113)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1061)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1381)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:1046)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:175)
... 17 more
The error originates from the MySQL server. You are trying to put a too big value into one of the columns.
You should check what value you are trying to add to the column and change the type for the column to something bigger.
For a better answer you need to supply more information on what data you are trying to add to each column.
I'm trying to migrate my hibernate 4.3 to hibernate 5.1.16 and I am ending up with QuerySyntaxException which am not able to figure after one week.
I am using annotation for mapping and I checked my queries all of those uses the same name of my entity class, there is no conflict in the name in my queries which am sure and also the point is it worked with Hibernate 4.3.
All the solution in the web is only pointing to naming conflicts.__Maintence is my first table and the mapping issue is pointing at this table.
Here is my hibernate.cfg which I use for mapping.
<mapping class="wadetech.DB.entity.__Maintenance"/>
This is my __Maintenance class
#Entity
#Table(name = "__maintenance", uniqueConstraints = #UniqueConstraint(columnNames = "name"))
public class __Maintenance implements java.io.Serializable {
This is my __MaintenanceDAO
public Collection<__Maintenance> getMaintenanceByName(String name){
String query = "";
query += "select m from __Maintenance m";
query += " where m.name = :name ";
query += " order by ";
query += " m.startDate desc, m.idMaintenance desc";
return super.list(query, "name", name);
}
And here is my exception
wadetech.exceptions.InfrastructureException: org.hibernate.hql.internal.ast.QuerySyntaxException: __Maintenance is not mapped [select m from __Maintenance m where m.name = :name order by m.startDate desc, m.idMaintenance desc]
at wadetech.DB.base.BaseDAO.anonymousFindByQuery(BaseDAO.java:267)
at wadetech.DB.base.BaseDAO.findByQuery(BaseDAO.java:255)
at wadetech.DB.base.BaseDAO.list(BaseDAO.java:243)
at wadetech.DB.DAOS.__MaintenanceDAO.getMaintenanceByName(__MaintenanceDAO.java:78)
at com.at.project.utils.runtime.RuntimeModifier.HasExecuted(RuntimeModifier.java:128)
at wadetech.listeners.ModificationScriptStartupListener.contextInitialized(ModificationScriptStartupListener.java:47)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:5016)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5528)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1575)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1565)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: __Maintenance is not mapped [select m from __Maintenance m where m.name = :name order by m.startDate desc, m.idMaintenance desc]
at org.hibernate.hql.internal.ast.QuerySyntaxException.generateQueryException(QuerySyntaxException.java:79)
at org.hibernate.QueryException.wrapWithQueryString(QueryException.java:103)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:217)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:141)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:115)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:76)
Am also adding a section of my HibernateUtil as I have my doubts this is causing due to some transaction issues which I changed after moving to 5.1
Before I used tx.wasCommitted();
which I can't use anymore as was Committed is omitted in hibernate 5.1 so I changed it to the below code tx.getStatus() == TransactionStatus.COMMITTED
Here is my hibernateUtil
public static void beginTransaction(boolean readOnly) throws InfrastructureException {
try {
if( currentConnectionMode == ConnectionMode.MASTER_SLAVE && readOnly ) {
// it is a readOnly tx
Transaction tx = readOnlyThreadTransaction.get();
if (null == tx || tx.getStatus() == TransactionStatus.COMMITTED || tx.getStatus() == TransactionStatus.ROLLED_BACK) {
tx = getReadOnlySession().beginTransaction();
readOnlyThreadTransaction.set(tx);
}
} else {
Transaction tx = threadTransaction.get();
if (null == tx || tx.getStatus() == TransactionStatus.COMMITTED || tx.getStatus() == TransactionStatus.ROLLED_BACK) {
tx = getSession().beginTransaction();
threadTransaction.set(tx);
}
} // end if
} // end try
catch (HibernateException ex) {
WLog.DAOLogger.error("Begin transaction", ex);
throw new InfrastructureException(ex);
} // end catch
}
I want to stick on with hibernate 5.1 and don't want to migrate to hibernate 5.2 as 5.2 uses jdk 8+. I prefer hibernate 5.1 because I strictly need to use jdk 1.7
So finally I solve the above issue was.Even though the exception din't help to point the issue. The real problem was at hibernateUtils.
Before this was how my hiberenate utils for hibernate 4.3.
serviceRegistry = new StandardServiceRegistryBuilder().applySettings(
configuration.getProperties()).build();
sessionFactory = configuration.configure().buildSessionFactory(serviceRegistry);
and I changed it to
registry = new StandardServiceRegistryBuilder().configure().build();
MetadataSources sources = new MetadataSources(registry);
Metadata metadata = sources.getMetadataBuilder().build();
sessionFactory = metadata.getSessionFactoryBuilder().build();
I am recently working on a task where I am refactoring an old web project. First I tried to run the project on my local weblogic instance before starting refactoring.
While I try to deploy the application I got a hibernate exception as follows ==>
Caused By: org.hibernate.AnnotationException: Unknown Id.generator: unique-id
at org.hibernate.cfg.BinderHelper.makeIdGenerator(BinderHelper.java:428)
at org.hibernate.cfg.AnnotationBinder.bindId(AnnotationBinder.java:1901)
at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:1279)
at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:754)
at org.hibernate.cfg.AnnotationConfiguration.processArtifactsOfType(AnnotationConfiguration.java:546)
Truncated. see log file for complete stacktrace
The exception above implying that it couldn't find the id generator named "unique-id" . Then I dig in to the code and see that the id field in the entity is string. and there is a custom ID generator class that is implementing hibernate IdentifierGenerator class where it is calling a db function for generating alphanumeric id for each time it is called. Below is piece of code in the entity class where it defines the type of id generation.
#Id
#Column(name = "ID", nullable = false, length = 18)
#GenericGenerator(name = "unique-id", strategy = "com.common.entity.RowIdGenerator")
#GeneratedValue(strategy = GenerationType.IDENTITY, generator = "unique-id")
private String id;
And here is the RowIdGenerator class for generating alphanumeric id.
public class RowIdGenerator implements IdentifierGenerator
{
private final static String SQL_TEXT = "SELECT TCC.F_ROW_ID_GEN FROM DUAL";
#Override
public Serializable generate(SessionImplementor sessionImplemetor, Object object) throws HibernateException
{
return this.getNextNumber(sessionImplemetor);
}
private String getNextNumber(SessionImplementor session)
{
try
{
ResultSet rs = null;
PreparedStatement statement = null;
try
{
statement = session.getBatcher().prepareSelectStatement(SQL_TEXT);
rs = statement.executeQuery();
String nextValue = null;
if (rs.next())
nextValue = rs.getString(1);
if (nextValue == null)
throw new HibernateException("is is null.");
return nextValue;
}
finally
{
if (rs != null)
rs.close();
if (statement != null)
session.getBatcher().closeStatement(statement);
}
} catch (SQLException sqle)
{
throw JDBCExceptionHelper.convert(session.getFactory().getSQLExceptionConverter(), sqle, "could not fetch initial value for increment generator", SQL_TEXT);
}
}
}
What may cause this error? I see that the generator named "unique-id" is defined and annotated. As far as I know there is no error in the code, maybe it is because of the configuration of my local weblogic instance but Any comment and advice would be appreciated.
regards
You can auto generate only number as ids.Auto generation for other types like String is not supported by hibernate
I want to get serial numbers with the help of database.
Here is what I want:
1.read the entity from database and lock it
2.increase the serial number and upadte the entity.
I am asuming the first thread can lock the record and the other thread won't work until the first thread commits its transaction, however, I got the opposite of what I want.
below is my code:
Repository:
public interface ActivityNoGeneratorRepository extends BaseRepository<ActivityNoGenerator, Long> {
#Lock(LockModeType.PESSIMISTIC_WRITE)
#Query(value = "select generator from ActivityNoGenerator generator where id=:id")
ActivityNoGenerator getGeneratorByIdForUpdate(#Param("id") Long id);
}
Service:
#Service
public class ActivityNoGeneratorServiceImpl implements IActivityNoGeneratorService {
#Autowired
private ActivityNoGeneratorRepository activityNoGeneratorRepository;
#Override
#Transactional
public String getActivityNo() {
ActivityNoGenerator activityNoGenerator = activityNoGeneratorRepository.getGeneratorByIdForUpdate(1L);
System.out.println(1);
Integer currentValue = activityNoGenerator.getCurrentValue() + 1;
if (!StringUtils.equals(DateFormatUtils.format(new Date(), "yyyyMM"), DateFormatUtils.format(activityNoGenerator.getLastAccessTime(), "yyyyMM"))) {
currentValue = 1;
}
String serialNum = String.format("%0" + activityNoGenerator.getWidth() + "d", currentValue);
String activityNo = activityNoGenerator.getPrefix() + activityNoGenerator.getPlatformCode() + DateFormatUtils.format(new Date(), "yyyyMM") + serialNum;
activityNoGenerator.setCurrentValue(currentValue);
activityNoGenerator.setLastAccessTime(new Date());
activityNoGeneratorRepository.save(activityNoGenerator);
return activityNo;
}
}
Test:
public class IActivityNoGeneratorServiceTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath*:spring/applicationContext.xml");
final IActivityNoGeneratorService activityNoGeneratorService = applicationContext.getBean(IActivityNoGeneratorService.class);
for (int i = 0; i < 2; i++) {
new Thread(new Runnable() {
#Override
public void run() {
System.out.println(activityNoGeneratorService.getActivityNo());
}
}).start();
}
}
}
Result:
Hibernate:
select
activityno0_.id as id1_3_,
activityno0_.current_value as current_2_3_,
activityno0_.last_access_time as last_acc3_3_,
activityno0_.platform_code as platform4_3_,
activityno0_.platform_name as platform5_3_,
activityno0_.prefix as prefix6_3_,
activityno0_.step as step7_3_,
activityno0_.width as width8_3_
from
activity_no_generator activityno0_
where
activityno0_.id=? for update
Hibernate:
select
activityno0_.id as id1_3_,
activityno0_.current_value as current_2_3_,
activityno0_.last_access_time as last_acc3_3_,
activityno0_.platform_code as platform4_3_,
activityno0_.platform_name as platform5_3_,
activityno0_.prefix as prefix6_3_,
activityno0_.step as step7_3_,
activityno0_.width as width8_3_
from
activity_no_generator activityno0_
where
activityno0_.id=? for update
1
1
Hibernate:
update
activity_no_generator
set
current_value=?,
last_access_time=?,
platform_code=?,
platform_name=?,
prefix=?,
step=?,
width=?
where
id=?
Hibernate:
update
activity_no_generator
set
current_value=?,
last_access_time=?,
platform_code=?,
platform_name=?,
prefix=?,
step=?,
width=?
where
id=?
Exception in thread "Thread-6" org.springframework.orm.jpa.JpaSystemException: commit failed; nested exception is org.hibernate.TransactionException: commit failed
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:333)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:483)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:290)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy44.getActivityNo(Unknown Source)
at com.lemall.srd.pop.activity.oa.service.IActivityNoGeneratorServiceTest$1.run(IActivityNoGeneratorServiceTest.java:18)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.hibernate.TransactionException: commit failed
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:187)
at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:77)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:517)
... 10 more
Caused by: org.hibernate.TransactionException: unable to commit against JDBC connection
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doCommit(JdbcTransaction.java:116)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:180)
... 12 more
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:404)
at com.mysql.jdbc.Util.getInstance(Util.java:387)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:950)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3966)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3902)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2526)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2673)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2545)
at com.mysql.jdbc.ConnectionImpl.commit(ConnectionImpl.java:1614)
at com.zaxxer.hikari.pool.ProxyConnection.commit(ProxyConnection.java:355)
at com.zaxxer.hikari.pool.HikariProxyConnection.commit(HikariProxyConnection.java)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doCommit(JdbcTransaction.java:112)
... 13 more
HD1020012017050631
Process finished with exit code 0
I debug my code and find the second thread executed without waiting the first thread commit.
Any clue what mistake I make? Thanks very much!
What I see is that you are missing the #Transactional annotation in your repository method which might be the reason that your service method and repo method are running in two different transactions. Also use the Propagation.Required option in your transactional annotation.