InvalidDataAccessResourceUsageException: org.hibernate.exception.SQLGrammarException: - java

I have the following problem I have been stuck for a while:
I get this error:
org.springframework.dao.InvalidDataAccessResourceUsageException: could not prepare statement; SQL [call next value for hibernate_sequence]; nested exception is org.hibernate.exception.SQLGrammarException: could not prepare statement
I found out that people with this error get it because they use reserve words for table names but I do not think this is my issue.
My two model classes are as follows. I am skipping the getters/setters and consturctors
#Entity
#Table(name = "GATEWAY_MODEL")
public class GetewayModel implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "serial_number", nullable = false, length = 12, updatable = true)
private String serialNumber;
#Column(name = "name", nullable = false, length = 12, updatable = true)
private String name;
#Column(name = "ipFour", nullable = false, length = 12, updatable = true)
private String ipFour;
#Column(name = "peripheral_devices", updatable = true)
#OneToMany(cascade = CascadeType.ALL, mappedBy = "gateway")
private Set<PeripheralDevicesModel> peripheralDevices = new HashSet<PeripheralDevicesModel>();
#Entity
#Table(name = "PERIPHERAL_DIVICES_MODEL")
public class PeripheralDevicesModel {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "uID", nullable = false)
private String uID;
#Column(name = "vendor", nullable = false)
private String vendor;
#Column(name = "date_created", nullable = false)
private Date dateCreated;
#Enumerated(EnumType.STRING)
#Column(name = "status")
private Status status;
#JsonIgnore
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "gateway")
private GetewayModel gateway;
Then in the main class I try to put some data like this:
#Bean
CommandLineRunner initDatabase(GatewayRepository gatewayRepo, PeripheralDevicesRepository devicesRepo) {
Set<PeripheralDevicesModel> devicesSet = new HashSet<>();
GetewayModel gateway = new GetewayModel();
gateway.setId(123l);
gateway.setSerialNumber("1123");
gateway.setName("gateway");
gateway.setIpFour("1.160.10.240");
PeripheralDevicesModel devices = new PeripheralDevicesModel();
devices.setId(1234l);
devices.setuID("2");
devices.setDateCreated(new Date());
devices.setGateway(gateway);
devices.setStatus(Status.OFFLINE);
devices.setVendor("vendor");
devicesSet.add(devices);
gateway.setPeripheralDevices(devicesSet);
return args -> {
gatewayRepo.save(gateway);
devicesRepo.save(devices);
};
I am guessing that are is some issue because of the OneToMany Relationship in my model data.
I bit more from the stack trace
call next value for hibernate_sequence
2020-06-26 08:34:53 - SQL Error: 90036, SQLState: 90036
2020-06-26 08:34:53 - Sequence "HIBERNATE_SEQUENCE" not found; SQL statement:
call next value for hibernate_sequence [90036-200]
2020-06-26 08:34:53 -
Do you have any idea how to resolve this or why it is not working.
Thanks
configuration.properties:
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
# Enabling H2 Console
spring.h2.console.enabled=true
# Custom H2 Console URL
spring.h2.console.path=/h2
spring.jpa.hibernate.ddl-auto=none
#Turn Statistics on and log SQL stmts
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.generate_statistics=false
#logging.level.org.hibernate.type=trace
#logging.level.org.hibernate.stat=debug
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} - %msg%n
Update:
After making GenerationType.IDENTITY I got the following error now:
Hibernate:
select
getewaymod0_.id as id1_0_1_,
getewaymod0_.ip_four as ip_four2_0_1_,
getewaymod0_.name as name3_0_1_,
getewaymod0_.serial_number as serial_n4_0_1_,
peripheral1_.gateway as gateway5_1_3_,
peripheral1_.id as id1_1_3_,
peripheral1_.id as id1_1_0_,
peripheral1_.date_created as date_cre2_1_0_,
peripheral1_.gateway as gateway5_1_0_,
peripheral1_.uid as uid3_1_0_,
peripheral1_.vendor as vendor4_1_0_
from
gateway_model getewaymod0_
left outer join
peripheral_divices_model peripheral1_
on getewaymod0_.id=peripheral1_.gateway
where
getewaymod0_.id=?
2020-06-26 16:42:04 - SQL Error: 42102, SQLState: 42S02
2020-06-26 16:42:04 - Table "GATEWAY_MODEL" not found; SQL statement:
select getewaymod0_.id as id1_0_1_, getewaymod0_.ip_four as ip_four2_0_1_, getewaymod0_.name as name3_0_1_, getewaymod0_.serial_number as serial_n4_0_1_, peripheral1_.gateway as gateway5_1_3_, peripheral1_.id as id1_1_3_, peripheral1_.id as id1_1_0_, peripheral1_.date_created as date_cre2_1_0_, peripheral1_.gateway as gateway5_1_0_, peripheral1_.uid as uid3_1_0_, peripheral1_.vendor as vendor4_1_0_ from gateway_model getewaymod0_ left outer join peripheral_divices_model peripheral1_ on getewaymod0_.id=peripheral1_.gateway where getewaymod0_.id=? [42102-200]
2020-06-26 16:42:04 - HHH000327: Error performing load command
org.hibernate.exception.SQLGrammarException: could not prepare statement

I changed 2 things(besides the few grammar/typo errors in your code):
Added cascade=CascadeType.ALL as follows:
#JsonIgnore
#ManyToOne(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "gateway")
private GatewayModel gateway;
You can't add an entity, which has columns with nullable = false:
devices.setGateway(new GetewayModel());
devices.setGateway(gateway);
Otherwise, it's working fine on H2.
UPDATE:
Grammar/typo errors to look for:
#Table(name = "PERIPHERAL_DIVICES_MODEL") needs to be #Table(name = "PERIPHERAL_DEVICES_MODEL")
public class GetewayModel needs to be public class GatewayModel
private GetewayModel gateway; needs to be private GatewayModel gateway;

Ran into the same problem. The difference was that I did not specify strategy in #GeneratedValues. Turns out the default strategy is GeneratedType.AUTO.
So Simon Martinelli's comment solves my issue, by explicitly specify #GeneratedValue(strategy = GenerationType.IDENTITY) for the id column/field.
This article summarises the strategies nicely.
GenerationType.Identity does not create any additional sequence tables like GenerationType.AUTO / GenerationType.SEQUENCE and also maintain the sequences in every table starts from 0, rather than maintaining the sequence number across the tables like GenerationType.AUTO does it.
GenerationType.AUTO generates one more table named hibernate_sequences for maintaining the sequences.
GenerationType.SEQUENCE is purely customizable, probably every auto generation field would have configured with separate sequences.

Related

Why jpa manyToOne lazy fetch is unavailable, it still lead to useless Association query

#JsonIgnoreProperties({"bmsPost"})
#ManyToOne(optional = true,fetch = FetchType.LAZY)
#JoinColumn(name = "user_id", nullable = false)
private UmsUser umsUser;
#JsonIgnoreProperties({"umsUser"})
#Column(name = "create_time", nullable = false)
private Date createTime;
#OneToMany(mappedBy = "umsUser",cascade=CascadeType.ALL,fetch=FetchType.LAZY)
// #JoinColumn(name="user_id",referencedColumnName="id")
private List<BmsPost> bmsPost;
I just want to select BmsPost, but it selects BmsPost and UmsUser
List<BmsPost> findAllByTitle(String title);
Result:
Hibernate: select bmspost0_.id as id1_1_, bmspost0_.collects as collects2_1_, bmspost0_.comments as comments3_1_, bmspost0_.content as content4_1_, bmspost0_.create_time as create_t5_1_, bmspost0_.essence as essence6_1_, bmspost0_.modify_time as modify_t7_1_, bmspost0_.section_id as section_8_1_, bmspost0_.title as title9_1_, bmspost0_.top as top10_1_, bmspost0_.user_id as user_id11_1_, bmspost0_.view as view12_1_ from bms_post bmspost0_ where bmspost0_.title=?
Hibernate: select umsuser0_.id as id1_3_0_, umsuser0_.active as active2_3_0_, umsuser0_.alias as alias3_3_0_, umsuser0_.avatar as avatar4_3_0_, umsuser0_.bio as bio5_3_0_, umsuser0_.create_time as create_t6_3_0_, umsuser0_.email as email7_3_0_, umsuser0_.mobile as mobile8_3_0_, umsuser0_.modify_time as modify_t9_3_0_, umsuser0_.password as passwor10_3_0_, umsuser0_.role_id as role_id11_3_0_, umsuser0_.score as score12_3_0_, umsuser0_.status as status13_3_0_, umsuser0_.token as token14_3_0_, umsuser0_.username as usernam15_3_0_ from ums_user umsuser0_ where umsuser0_.id=?
[BmsPost{id='1408691924814835713', title='ds', content='dsd', userId='1349618748226658305', comments=0, collects=0, view=0,top=false, essence=false, sectionId=0, createTime=2021-06-26 15:41:42.0,modifyTime=null, umsUser=com.example.demo.Entity.UmsUser#38d115a4}]
How to avoid it?
Do you define List bmsPost in your DTO?
if you define that property in your DTO when you get your Data from DB Hibernate create a query for them to get data it needs

Hibernate OneToOne between PK's with lazy behaviour

I'm trying to achieve to have an entity called MyEntity along with another entity called MyEntityInfo using Hibernate 5.3.13.Final with annotations under Wildfly 18.
The idea is to have MyEntity store some commonly requested fields, and MyEntityInfo store some rarely requested fields. Both share the same primary key called SID (Long), and there is a FK from Info's SID to Entity's SID. There can be entities without info.
Normally you will not require the additional info. For example, I don't want the info entity to be fetched when I query my entity like this:
MyEntityImpl entity = em.find(MyEntityImpl.class, 1L);
However, when I run this code, I find that there's a second query, fetching the Info entity along the main one, as in an EAGER behaviour.
I'm mapping the relationship using #OneToOne. I've tried several combinations of FetchType, optional and #LazyToOne, but so far without success.
Here is the code for both MyEntity and MyEntityInfo classes (additional getters and setters removed):
MyEntity (ID generator is a custom sequence generator):
#Entity
#Table(name = MyEntityImpl.TABLE_NAME)
public class MyEntityImpl {
public static final String TABLE_NAME = "TMP_MY_ENTITY";
#Id
#GeneratedValue(strategy = GenerationType.TABLE, generator = "GEN_" +
TABLE_NAME)
#GenericGenerator(name = "GEN_" +
TABLE_NAME, strategy = CoreIdGenerator.ID_GENERATOR, parameters = {
#Parameter(name = "tableName", value = TABLE_NAME) })
#Column(name = "sid", nullable = false, unique = true)
private Long sid;
#OneToOne(mappedBy = "myEntity", cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = true)
#LazyToOne(LazyToOneOption.NO_PROXY)
private MyEntityInfoImpl info;
#Column
private String field;
MyEntityInfo:
#Entity
#Table(name = MyEntityInfoImpl.TABLE_NAME)
public class MyEntityInfoImpl {
public static final String TABLE_NAME = "TMP_MY_ENTITY_INFO";
#Id
#Column(name = "SID", nullable = false, unique = true)
private Long sid;
#OneToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "SID", referencedColumnName = "SID", insertable = false, updatable = false, nullable = false)
private MyEntityImpl myEntity;
#Column(name = "INFO_FIELD")
private String infoField;
I've tried this solution, but as I said, it didn't work for me:
Hibernate lazy loading for reverse one to one workaround - how does this work?
I've managed to do something somewhat similar using #OneToMany and managing data manually, but that's not what I'd like to do. However, another alternatives and information on whether this can be achieved or not using #OneToOne, or the right design pattern to do this are also welcome.
PS: Database tables creation for SQL Server, in case you want to try it:
create table TMP_MY_ENTITY (SID NUMERIC(19,0) NOT NULL, FIELD VARCHAR(100));
go
ALTER TABLE TMP_MY_ENTITY ADD CONSTRAINT PK_TMP_MY_ENTITY PRIMARY KEY CLUSTERED (SID);
go
create table TMP_MY_ENTITY_INFO (SID NUMERIC(19,0) NOT NULL, INFO_FIELD VARCHAR(100));
go
ALTER TABLE TMP_MY_ENTITY_INFO ADD CONSTRAINT PK_TMP_MY_ENTITY_INFO PRIMARY KEY CLUSTERED (SID);
go
CREATE SEQUENCE SEQ_TMP_MY_ENTITY START WITH 1 INCREMENT BY 1 MINVALUE 1 CACHE 20;
alter table TMP_MY_ENTITY_INFO add constraint FK_TMP_MY_ENT_INFO_MY_ENT FOREIGN KEY (SID) references TMP_MY_ENTITY(SID);
go
insert into TMP_MY_ENTITY(SID, FIELD) VALUES (NEXT VALUE FOR SEQ_TMP_MY_ENTITY, 'Field 1');
insert into TMP_MY_ENTITY_INFO(SID, INFO_FIELD) VALUES ((SELECT MAX(SID) FROM TMP_MY_ENTITY), 'Info 1');
insert into TMP_MY_ENTITY(SID, FIELD) VALUES (NEXT VALUE FOR SEQ_TMP_MY_ENTITY, 'Field 2');
insert into TMP_MY_ENTITY_INFO(SID, INFO_FIELD) VALUES ((SELECT MAX(SID) FROM TMP_MY_ENTITY), 'Info 2');
insert into TMP_MY_ENTITY(SID, FIELD) VALUES (NEXT VALUE FOR SEQ_TMP_MY_ENTITY, 'Field 3 no info');
-- DELETE ALL
drop table TMP_MY_ENTITY_INFO;
drop table TMP_MY_ENTITY;
drop sequence SEQ_TMP_MY_ENTITY;
After following #SternK link, and upgrading to Wildfly 19 and Hibernate 5.4.14, it finally worked by using #MapsId.
The right mapping to use is this:
MyEntity:
public class MyEntityImpl {
#OneToOne(mappedBy = "myEntity", cascade = CascadeType.REMOVE, fetch = FetchType.LAZY, optional = true)
#JoinColumn(name = "SID")
private MyEntityInfoImpl info;
MyEntityInfo:
public class MyEntityInfoImpl {
#OneToOne(fetch = FetchType.EAGER, optional = false)
#MapsId
#JoinColumn(name = "SID", referencedColumnName = "SID", insertable = false, updatable = false, nullable = false)
private MyEntityImpl myEntity;

Hibernate Lazy Loading Using SpringMVC

I'm having a big problem for which I can't find an answer.
I have a OneToOne bidirectional Lazy fetched relation between two entities, but when I query one of them, it eagerly fetch the other, even though I'm explicitly saying that it's Lazy.
According to what I've found, almost all from 2010 and back, says that that is the way hibernate behaves on OneToOne relations. This is my first time using Hibernate ever but I highly doubt that is true, and if it was that it still is true. But i can't find any recent information about it. Post1, Post2, Post3 as you can see, they are not really recent. So I wanted to know if that's still the case or maybe guide me to where I can find the answer, examples, anything would help really.
Here's what I'm doing, just in case I'm doing something wrong.
Note the classes has fewer attributes than the original, but all of them are columns of the entity, no FK, PK, or something like that.
User Entity
#Entity
#Table(name = "\"User\"")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "Id", unique = true, nullable = false)
private long id;
#Column(name = "Username", nullable = false, unique = true, length = 100)
private String username;
#Valid
#OneToOne(fetch = FetchType.LAZY, mappedBy = "user", cascade = CascadeType.ALL)
#JsonBackReference
private UserProfile userProfile;
//Getters and Setters
}
UserProfile Entity
#Entity
#Table(name = "UserProfile")
public class UserProfile {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#NotBlank
#Size(max = 100)
#Column(name = "FirstName", nullable = false, unique = false, length = 100)
private String firstName;
#NotBlank
#Size(max = 100)
#Column(name = "LastName", nullable = false, unique = false, length = 100)
private String lastName;
#Valid
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "UserId")
#JsonManagedReference
private User user;
//Getters and Setters
}
Test controller method
#RequestMapping(value = "/test", method = RequestMethod.GET)
public ResponseEntity<Void> test(){
User user = userService.findUserByUsername("admin");
if(user.getUserProfile() == null){
return new ResponseEntity<Void>(HttpStatus.OK);
}
return new ResponseEntity<Void>(HttpStatus.CONFLICT);
}
And the UserService simply calls the UserDao method, which is
#Override
public User findByUsername(String username) {
Criteria criteria = createEntityCriteria();
criteria.add(Restrictions.eq("username", username));
return (User) criteria.uniqueResult();
}
The result of that service is always Conflict. Even though I'm calling the UserService (Which is Transactional) and the direct relation is in UserProfile. The controller is not transactional.
The log:
2016-02-29 18:50:58 DEBUG SQL::logStatement:92 -
select
this_.Id as Id1_2_0_,
this_.Username as Username5_2_0_
from
Public.[User] this_
where
this_.Username=?
Hibernate:
select
this_.Id as Id1_2_0_,
this_.Username as Username5_2_0_
from
Public.[User] this_
where
this_.Username=?
2016-02-29 18:50:58 DEBUG Loader::debugf:384 - Result set row: 0
2016-02-29 18:50:58 DEBUG Loader::getRow:1514 - Result row: EntityKey[com.portal.model.user.User#1]
2016-02-29 18:50:58 DEBUG TwoPhaseLoad::doInitializeEntity:144 - Resolving associations for [com.portal.model.user.User#1]
2016-02-29 18:50:58 DEBUG Loader::loadEntity:2186 - Loading entity: [com.portal.model.user.UserProfile#1]
2016-02-29 18:50:58 DEBUG SQL::logStatement:92 -
select
userprofil0_.id as id1_18_0_,
userprofil0_.FirstName as FirstNam5_18_0_,
userprofil0_.LastName as LastName7_18_0_,
userprofil0_.UserId as UserId10_18_0_
from
Public.UserProfile userprofil0_
where
userprofil0_.UserId=?
Hibernate:
select
userprofil0_.id as id1_18_0_,
userprofil0_.FirstName as FirstNam5_18_0_,
userprofil0_.LastName as LastName7_18_0_,
userprofil0_.UserId as UserId10_18_0_
from
Public.UserProfile userprofil0_
where
userprofil0_.UserId=?
Is there something wrong? Am I doing something wrong?
Thanks for any help you can provide! Let me know if you need more info!

Hibernate One to Many Mapping is trying to update mapping column to null

I am using below mapping
#Entity
#Table(name = "test")
public class TestOrder implements Serializable {
#Id
#Column(name = "orderid", updatable = false)
protected Long orderId;
#OneToMany(cascade = {CascadeType.ALL})
#JoinColumn(name = "order_id_fk")
private List<TestDetails> details;
//getters and setters
}
#Entity
#Table(name="test_details")
public class TestDetails implements Serializable {
#Id
//Generator
#Column(name = "id", updatable = false, insertable = false)
protected Long id;
#Column(name="order_id_fk", updatable = false)
private Long orderId;
//getters and setters
}
When I update/insert the data, it's trying to update the order_id_fk to null
SQL [update test_details set order_id_fk'='null where order_id_fk'='? and id'='?]; constraint [null];
Any help is much appreciated.
Updating/Inserting using Spring Integration
<int-jpa:updating-outbound-gateway entity-class="com.aaaa.TestOrder" entity-manager-factory="myEntityManagerFactory" persist-mode="MERGE">
<int-jpa:transactional propagation="REQUIRED" transaction-manager="myTransactionManager" />
</int-jpa:updating-outbound-gateway>
You need to fetch values of TestDetails entity eagerly.
Just modify in your annotation with,
#OneToMany(fetch = FetchType.EAGER, mappedBy="testOrder", cascade=CascadeType.ALL)
Hope this will work.
I ran your code and it works correctly (when added #GeneratedValue(strategy = GenerationType.AUTO) to both IDs).
em.getTransaction().begin();
TestOrder to = new TestOrder();
TestDetails td1 = new TestDetails();
TestDetails td2 = new TestDetails();
TestDetails td3 = new TestDetails();
to.setDetails(Arrays.asList(new TestDetails[] {td1, td2, td3}));
em.persist(to);
em.getTransaction().commit();
what results in following sqls:
[03/07/14 10:03:30] INFO jdbc.sqlonly: insert into test (orderid) values (1)
[03/07/14 10:03:30] INFO jdbc.sqlonly: insert into test_details (order_id_fk, id) values (NULL, 2)
[03/07/14 10:03:30] INFO jdbc.sqlonly: insert into test_details (order_id_fk, id) values (NULL, 3)
[03/07/14 10:03:30] INFO jdbc.sqlonly: insert into test_details (order_id_fk, id) values (NULL, 4)
[03/07/14 10:03:30] INFO jdbc.sqlonly: update test_details set order_id_fk=1 where id=2
[03/07/14 10:03:30] INFO jdbc.sqlonly: update test_details set order_id_fk=1 where id=3
[03/07/14 10:03:30] INFO jdbc.sqlonly: update test_details set order_id_fk=1 where id=4
So, if the code you posted is the code which you compile then TestOrder entity is not able to generate its ID (lack of #GeneratedValue annotation).
In case of database generating IDs (i.e. using autonumbering) for this entity, you should set #GeneratedValue to IDENTITY to let your jpa provider know that it must reread inserted row afterwards. If jpa provider fails to reread id, it updates test_details order_id_fk column with null.
PS. Why didn't you set many-to-one relationship at TestDetails side?
You may have to change the entity like below. As far as I remember, if you are trying to set the foreign key of a column this works best.
#Entity
#Table(name="test_details")
public class TestDetails implements Serializable {
#Id
//Generator
#Column(name = "id", updatable = false, insertable = false)
protected Long id;
#Column(name="order_id_fk", updatable = false, insertable = false)
private TestOrder orderId;
//getters and setters
}

Cannot insert NULL into column

I am attempting to get Hibernate to lazy load some clobs. The loading portion is working just fine. The issue is when I try to create a new one. I started with advice from Blob lazy loading
Here are my mappings (Note the table structure is really really bad, there are multiple clobs on this table -- this example is simplified from my real model...).
#Entity #Table("TABLE_1")
public class BadDBDesign {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
#Column("table_id")
private long key;
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "table_id", referencedColumnName = "table_id",
insertable = true, updatable = false)
private BlobWrapperA;
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "table_id", referencedColumnName = "table_id",
insertable = true, updatable = false)
private BlobWrapperB;
}
#Entity #Table(name = "TABLE_1")
public class BlobWrapperA {
#Lob
#Column(name = "col_A", nullable = false)
#Type(type = "org.springframework.orm.hibernate3.support.BlobByteArrayType")
private byte[] blobColA;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "table_id")
private long Key;
}
#Entity #Table(name = "TABLE_1")
public class BlobWrapperB {
#Lob
#Column(name = "col_B", nullable = false)
#Type(type = "org.springframework.orm.hibernate3.support.BlobByteArrayType")
private byte[] blobColB;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "table_id")
private long Key;
}
Application boots just fine, am able to retrieve the data without loading the clobs (am able to retrieve them when needed via lazy loading), but when I attempt to create the new ones I receive the following stacktrace:
Hibernate:
insert
into
TABLE_1
(key, col_A, col_B)
values
(?, ?, ?)
2011-08-31 17:35:09,089 [http-8080-1] DEBUG org.springframework.jdbc.support.lob.DefaultLobHandler IP134.167.141.34 CV#f2a597b2-a185-4e89 P#71252 - Set bytes for BLOB with length 7136
2011-08-31 17:35:16,441 [http-8080-1] DEBUG org.springframework.jdbc.support.lob.DefaultLobHandler IP134.167.141.34 CV#f2a597b2-a185-4e89 P#71252 - Set bytes for BLOB with length 10946
Aug 31, 2011 5:35:50 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet online threw exception java.sql.SQLIntegrityConstraintViolationException: ORA-01400: cannot insert NULL into ("SCHEMA"."TABLE_1"."COL_A")
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:440)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:396)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:837)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:445)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:191)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:523)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:207)
at oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:1010)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1315)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3576)
at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:3657)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeUpdate(OraclePreparedStatementWrapper.java:1350)
at org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
at org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
Note the important piece where we see the lengths of the clobs immediately after the Hibernate insert statement from the generated SQL.
Edit: After looking at this early this morning, I realized that the issue was due to one of the Blobs had to be mapped with #JoinColumn(insertable = false, updatable = false), otherwise Hibernate would not start. As such of course it was attempting to insert Null into this column. So the new question becomes, can you lazily MULTIPLE clobs on a single table (using the same key). I'm guessing without a table redesign, I'm pretty much out of luck unless Oracle fixes the driver.
As much as it makes me want to vomit we needed to get this functionality without modifying the Database.
As such, I pulled out the common pieces into an Abstract class like such:
#MappedSuperclass #Table("TABLE_1")
public class BadDBDesign {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
#Column("table_id")
private long key;
#Column("small_value")
private String smallVarChar2Field;
}
The problem is I then have to extend this class for each of our blobs :( Thus our extended classes loook like:
public class BlobA extends BadDBDesign {
#Lob #Column("col_a")
#Type(type ="org.springframework.orm.hibernate3.support.BlobByteArrayType")
private byte[] blobColA;
}
public class BlobB extends BadDBDesign {
#Lob #Column("col_b")
#Type(type ="org.springframework.orm.hibernate3.support.BlobByteArrayType")
private byte[] blobColB;
}
Luckily we don't have any location where we more than one clob on any given page. This is still a maintenance nightmare, but was an acceptable trade-off (for the time-being) on getting the loads done more efficiently. I created DAO's for these, which the project didn't have prior; hopefully this will push the team in a good direction towards a proper abstraction layer, and we can hopefully completely remove these wasted POJOs in a future release.
Looks like in your BlobWrapperA class you have "nullable = false" set on that column. Or the column has a null constraint on the table itself in the database.
Oracle and Hibernate hate each other when it comes to LOB types, which stems from the fact that the Oracle driver is garbage. I believe I've run across this before, you should try setting the following system properties:
hibernate.jdbc.use_streams_for_binary=true
hibernate.jdbc.batch_size=0

Categories

Resources