I have some question about Pessimistic Locking in SQL Server? Here are my classes and test scenario;
Entity class:
#Data
#Entity(name = "mapping")
#Table(
uniqueConstraints =
#UniqueConstraint(
name = "UQ_MappingEntity",
columnNames = {
Constants.DATA_TYPE_VALUE,
Constants.DATA_TYPE_NAMESPACE_INDEX,
Constants.TENANT_ID,
Constants.ASSET_TYPE_NAME
}
)
)
public class MappingEntity {
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
private String id;
#Column(name = Constants.DATA_TYPE_VALUE)
private long dataTypeValue;
#Column(name = Constants.DATA_TYPE_NAMESPACE_INDEX)
private int dataTypeNamespaceIndex;
#Column(name = Constants.ASSET_TYPE_NAME)
private String assetTypeName;
#Column(name = Constants.TENANT_ID)
private String tenantId;
}
Repository class:
public interface MappingRepository extends JpaRepository<MappingEntity, String> {
#Lock(LockModeType.PESSIMISTIC_WRITE)
MappingEntity findMappingEntityWithLockByTenantIdAndAssetTypeName(
String tenantId, String assetTypeName);
}
Service code block:
#Transactional
public void deleteAspectType(String tenantId, String aspectTypeId) {
MappingEntity mappingEntity = mappingRepository.findMappingEntityWithLockByTenantIdAndAssetTypeName(tenantId, assetTypeName);
mappingRepository.delete(mappingEntity);
}
When I enable the hibernate logs. I see select query below.
select
mappingent0_.id as id1_1_,
mappingent0_.asset_type_name as asset_ty2_1_,
mappingent0_.data_type_namespace_index as data_typ3_1_,
mappingent0_.data_type_value as data_typ4_1_,
mappingent0_.tenant_id as tenant_i5_1_
from
mapping mappingent0_ with (updlock,
holdlock,
rowlock)
where
mappingent0_.tenant_id=?
and mappingent0_.asset_type_name=?
I have sent two delete request at the same time with same tenant_id but different asset_type_name;
Transaction-1: tenant_id = "testtenant", asset_type_name = "testname1"
Transaction-2: tenant_id = "testtenant", asset_type_name = "testname2"
Transaction-1 run select query and gets results, When Transaction-2 run select query it blocks. After Transaction-1 deletes and finishes the transaction, Transaction-2 get results and deletes.
I have two question;
What are the (updlock, holdlock, rowlock) use for? When I use these three same time, how does effect my query and transaction?
Why did Transaction-2 block when it run the query? Because Both transaction selected different rows.
Related
Creation of column with prefix and sequence using JPA and SQL Server.
I need some column (not primary key) with prefix and sequence, for example T1, T2, T3.
I've tried this:
CREATE SEQUENCE t_sequence START WITH 1 INCREMENT BY 1;
ALTER TABLE gate ADD T_NUM INT;
ALTER TABLE gate ADD T VARCHAR(30);
...
#Column(name = "T_NUM")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "t_sequence ")
#SequenceGenerator(name = "t_sequence ", t_sequence = "mir_sequence", allocationSize = 1, initialValue = 1)
private int tNum;
#Column(name = "T")
private String t;
...
#PrePersist
public void onCreate() {
super.onCreate();
t= "T" + this.tNum;
}
As a result I always have T0 in t column.
I have a SpringBoot 2.2.6 WebApp, I'm using java8, Apache Maven 3.6.3, JPA 2.2, Hibernate Core 5.4.12.Final.
I have a model similar to follow:
Entity Period that represent time period by a data:
#Entity
#Table
#Data
public class Period {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private LocalDate date;
}
an Entity Monitor, for each Period we can have more than one Monitor (1 -> N):
#Entity
#Table
#Data
public class Monitor {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String description;
#ManyToOne(optional = false, fetch = FetchType.LAZY)
#JoinColumn(name = "id_period", referencedColumnName = "id")
private Period period;
}
And a MonitorInstance Entity, for each Monitor we can have more MonitorInstance
#Entity
#Table
#Data
public class MonitorInstance {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String someData;
private String someOthers;
#ManyToOne(optional = false, fetch = FetchType.LAZY)
#JoinColumn(name = "id_monitor", referencedColumnName = "id")
#JoinColumn(name = "id_period", referencedColumnName = "id_period")
private Monitor monitor;
}
On MonitorInstance I added a second column which references not a primary key but a foreign key:
#JoinColumn(name = "id_period", referencedColumnName = "id_period")
These because if I have TABLE Period as follows:
----------------------
-- ID -- DATA --------
-- 1 -- 2022-03-03 --
-- 2 -- 2022-06-03 --
And a TABLE Monitor as follows:
-------------------------------------
-- ID -- DESCRIPTION --- ID_PERIOD --
-- 1 -- tes1 --- 1
-- 2 -- tes1 --- 2 --
And try to insert (manually, via batch, via jpa or in any other way) something like:
insert into
monitor_instance
(id, some_data, some_others, id_monitor, id_period)
values
(1, 'data', 'otherdata', 1, 2);
Should return an IntegrityConstraintViolation because of Monitor with id 1 is linked with Period with id 1.
And it works! The application started, the db (even via flyway) is created but sometimes when I perform a clean verify the console log me up the follow error:
org.hibernate.MappingException: Unable to find column with logical name "id_period" in table "period"
There are a lot of question about this kind of error even in this forum. I read them all and, most of them are confusing and bad explained (at least for me obviously), in any case I didn't find a working solution or an explanation why this kind of error happens.
Clearly this is an example situation, the real DB is a little bit complex but the logic is the same.
Can someone help me to find out what happens or, at least, how to improve my entities so that the result is the same but that problem no longer occurs?
N.B.: I want to remember that the error is not systemic! The code is still the same and sometimes the errors show up and sometimes not (my GitLab pipeline pages seems a traffic light).
Server inform error
HTTP Status 500 - Request processing failed; nested exception is
org.springframework.dao.TransientDataAccessResourceException:
StatementCallback; SQL [SELECT * FROM Accounts INNER JOIN Comment ON
Comment.Account_ID=Accounts.Account_ID WHERE Comment.Place_ID=3]; The
column name Accounts.Account_ID is not valid.; nested exception is
com.microsoft.sqlserver.jdbc.SQLServerException: The column name
Accounts.Account_ID is not valid.
This is my code in DAO
public List<LoadCommentDTO> loadComment(int placeId) {
String sql = "SELECT * FROM Accounts INNER JOIN Comment ON Comment.Account_ID=Accounts.Account_ID WHERE Comment.Place_ID="+ placeId ;
RowMapper<LoadCommentDTO> rowMapper = new CommentRowMapper();
List<LoadCommentDTO> listComment = jdbcTemplate.query(sql, rowMapper);
return listComment;
}
protected class CommentRowMapper implements RowMapper<LoadCommentDTO> {
#Override
public LoadCommentDTO mapRow(ResultSet rs, int rowNum) throws SQLException {
LoadCommentDTO loadCommentDTO = new LoadCommentDTO();
CommentDTO commentDTO = new CommentDTO();
AccountDTO accountDTO = new AccountDTO();
accountDTO.setAccountID(rs.getInt("Accounts.Account_ID"));
accountDTO.setAvatar_path(rs.getString("Accounts.Avatar_path"));
accountDTO.setFirstname(rs.getString("Accounts.Firstname"));
accountDTO.setLastname(rs.getString("Accounts.Lastname"));
commentDTO.setAccount_Id(rs.getInt("Comment.Account_ID"));
commentDTO.setDescription(rs.getString("CommentDescription"));
commentDTO.setPlace_ID(rs.getInt("CommentPlace_ID"));
commentDTO.setC_Date(rs.getString("CommentC_Date"));
loadCommentDTO.setAccountDTO(accountDTO);
loadCommentDTO.setCommentDTO(commentDTO);
return loadCommentDTO;
}
}
My Entity class
#Entity
class MasterStccycode{
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 3)
#Column(name = "CODE")
private String code;
#Size(max = 100)
#Column(name = "DESC")
private String desc;
}
my JPA Query
SELECT t.code, t.desc FROM MasterStccycode t
then I have this following exception
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.0.v20110604-r9504): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.microsoft.sqlserver.jdbc.SQLServerException: Incorrect syntax near the keyword 'DESC'.
Error Code: 156
Call: SELECT CODE, DESC FROM master_stccycode
Query: ReportQuery(referenceClass=MasterStccycode sql="SELECT CODE, DESC FROM master_stccycode")
I know the solution is to wrap the DESC keyword with [] into [DESC] but how can I do this on JPA QL?
DESC is a reserved word on most databases. You should rename the field.
You could also quote the field, but just renaming it would be best.
#Column(name = "\"DESC\"")
When I execute
#NamedQuery(name = "GroupsHasStudent.findByGroupsidGroups", query = "SELECT g FROM GroupsHasStudent g WHERE g.groupsHasStudentPK.groupsidGroups = :groupsidGroups"),
of GroupsHasStudent entity, the result is generated correct. But another NativeQuery
getEntityManager().
createNativeQuery(
"SELECT d.idDiscipline, d.name, gy.idGroupsYear, gy.year, g.idGroups "
+ "FROM Discipline d, Groupsyear gy, Groups g, GroupsHasStudent ghs "
+ "WHERE ghs.groupsHasStudentPK.groupsidGroups=2").
getResultList();
throws the Exception
Internal Exception:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:
Table 'mydb.groupshasstudent' doesn't exist
Actually I do don't have such table in db, but the correct name is *groups_has_student* which is specified in #Table:
(My entity:)
#Entity
#Table(name = "groups_has_student")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "GroupsHasStudent.findAll", query = "SELECT g FROM GroupsHasStudent g"),
#NamedQuery(name = "GroupsHasStudent.findByGroupsidGroups", query = "SELECT g FROM GroupsHasStudent g WHERE g.groupsHasStudentPK.groupsidGroups = :groupsidGroups"),
#NamedQuery(name = "GroupsHasStudent.findByStudentUserslogin", query = "SELECT g FROM GroupsHasStudent g WHERE g.groupsHasStudentPK.studentUserslogin = :studentUserslogin")})
public class GroupsHasStudent implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
protected GroupsHasStudentPK groupsHasStudentPK;
public GroupsHasStudent() {
}
And even when I rename table in mysql to groupshasstudent there is another Exception
Unknown column 'ghs.groupsHasStudentPK.studentUserslogin' in 'where clause'
І це сумно..
It's not a native (SQL) query, it's a JPQL query, therefore you should use createQuery() instead of createNativeQuery().