public class JSONmapper {
public static class Person{
#QuerySqlField(index = true)
int id;
#QuerySqlField(index = true)
String name;
}
public static void main(String[] args) {
Map<String,Object> serdeProps = new HashMap<>();
serdeProps.put("json.value.type",Person.class);
final Deserializer<Person> PersonDeserializer = new KafkaJsonDeserializer<>();
PersonDeserializer.configure(serdeProps, false);
Properties prop = new Properties();
prop.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,"localhost:9092");
prop.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
prop.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, PersonDeserializer.getClass().getName());
prop.put(ConsumerConfig.GROUP_ID_CONFIG,"JSONmapper1");
prop.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG,"earliest");
KafkaConsumer<String,Person> consumer = new KafkaConsumer<>(prop);
consumer.subscribe(Collections.singleton("JsonMapper1"));
IgniteConfiguration config = new IgniteConfiguration();
Ignite ignite = Ignition.start(config);
CacheConfiguration<String, Person> cc = new CacheConfiguration<>("PersonCache");
cc.setCacheMode(CacheMode.PARTITIONED);
cc.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
cc.setIndexedTypes(String.class,Person.class);
IgniteCache<java.lang.String,Person> cache = ignite.getOrCreateCache(cc);
Map<String, Person> batch = new HashMap<>();
while(true)
{
ConsumerRecords<String, Person> records = consumer.poll(Duration.ofMillis(100));
for (ConsumerRecord<String, Person> record:records){
batch.put(record.key(),record.value());
}
cache.putAll(batch);
batch.clear();
}
}
}
Hi all I am trying to send JSON data coming out of Kafka to Ignite cache and view it as a table. After running this code I could observe that data is transferred to cache, confirmed this with visorcmd. I triggered sqlline.bat from setup with PersonCache schema as it was showing !tables. But unable to query "Select * from Person". It is giving me error that "Failed to set schema for DB connection for thread".
Please enlight and help regarding this.
SEVERE: Failed to execute SQL query [reqId=2, req=JdbcQueryExecuteRequest [schemaName=PERSONCACHE, pageSize=1024, maxRows=0, sqlQry=select * from PersonCache.PERSON, args=Object[] [], stmtType=ANY_STATEMENT_TYPE, autoCommit=true, partResReq=false, super=JdbcRequest [type=2, reqId=2]]]
class org.apache.ignite.internal.processors.query.IgniteSQLException: Failed to set schema for DB connection for thread [schema=PERSONCACHE]
at org.apache.ignite.internal.processors.query.h2.H2ConnectionWrapper.connection(H2ConnectionWrapper.java:81)
at org.apache.ignite.internal.processors.query.h2.QueryParser.parseH2(QueryParser.java:319)
at org.apache.ignite.internal.processors.query.h2.QueryParser.parse0(QueryParser.java:210)
at org.apache.ignite.internal.processors.query.h2.QueryParser.parse(QueryParser.java:131)
at org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing.querySqlFields(IgniteH2Indexing.java:1103)
at org.apache.ignite.internal.processors.query.GridQueryProcessor$3.applyx(GridQueryProcessor.java:2406)
at org.apache.ignite.internal.processors.query.GridQueryProcessor$3.applyx(GridQueryProcessor.java:2402)
at org.apache.ignite.internal.util.lang.IgniteOutClosureX.apply(IgniteOutClosureX.java:36)
at org.apache.ignite.internal.processors.query.GridQueryProcessor.executeQuery(GridQueryProcessor.java:2919)
at org.apache.ignite.internal.processors.query.GridQueryProcessor.lambda$querySqlFields$1(GridQueryProcessor.java:2422)
at org.apache.ignite.internal.processors.query.GridQueryProcessor.executeQuerySafe(GridQueryProcessor.java:2460)
at org.apache.ignite.internal.processors.query.GridQueryProcessor.querySqlFields(GridQueryProcessor.java:2396)
at org.apache.ignite.internal.processors.query.GridQueryProcessor.querySqlFields(GridQueryProcessor.java:2354)
at org.apache.ignite.internal.processors.odbc.jdbc.JdbcRequestHandler.executeQuery(JdbcRequestHandler.java:615)
at org.apache.ignite.internal.processors.odbc.jdbc.JdbcRequestHandler.doHandle(JdbcRequestHandler.java:310)
at org.apache.ignite.internal.processors.odbc.jdbc.JdbcRequestHandler.handle(JdbcRequestHandler.java:247)
at org.apache.ignite.internal.processors.odbc.ClientListenerNioListener.onMessage(ClientListenerNioListener.java:195)
at org.apache.ignite.internal.processors.odbc.ClientListenerNioListener.onMessage(ClientListenerNioListener.java:49)
at org.apache.ignite.internal.util.nio.GridNioFilterChain$TailFilter.onMessageReceived(GridNioFilterChain.java:279)
at org.apache.ignite.internal.util.nio.GridNioFilterAdapter.proceedMessageReceived(GridNioFilterAdapter.java:109)
at org.apache.ignite.internal.util.nio.GridNioAsyncNotifyFilter$3.body(GridNioAsyncNotifyFilter.java:97)
at org.apache.ignite.internal.util.worker.GridWorker.run(GridWorker.java:120)
at org.apache.ignite.internal.util.worker.GridWorkerPool$1.run(GridWorkerPool.java:70)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.h2.jdbc.JdbcSQLException: Schema "PERSONCACHE" not found [90079-197]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:357)
at org.h2.message.DbException.get(DbException.java:179)
at org.h2.message.DbException.get(DbException.java:155)
at org.h2.engine.Database.getSchema(Database.java:1808)
at org.h2.engine.Session.setCurrentSchemaName(Session.java:1317)
at org.h2.jdbc.JdbcConnection.setSchema(JdbcConnection.java:1989)
at org.apache.ignite.internal.processors.query.h2.H2ConnectionWrapper.connection(H2ConnectionWrapper.java:76)
... 25 more
At SQLline end :
Error: Failed to set schema for DB connection for thread [schema=PERSONCACHE] (state=50000,code=1)
java.sql.SQLException: Failed to set schema for DB connection for thread [schema=PERSONCACHE]
at org.apache.ignite.internal.jdbc.thin.JdbcThinConnection.sendRequest(JdbcThinConnection.java:901)
at org.apache.ignite.internal.jdbc.thin.JdbcThinStatement.execute0(JdbcThinStatement.java:231)
at org.apache.ignite.internal.jdbc.thin.JdbcThinStatement.execute(JdbcThinStatement.java:559)
at sqlline.Commands.execute(Commands.java:823)
at sqlline.Commands.sql(Commands.java:733)
at sqlline.SqlLine.dispatch(SqlLine.java:795)
at sqlline.SqlLine.begin(SqlLine.java:668)
at sqlline.SqlLine.start(SqlLine.java:373)
at sqlline.SqlLine.main(SqlLine.java:265)
First of all, in order to have an Apache Ignite SQL table based on some POJO, you must do one of the following:
1)If you are going to configure the cache via XML, you must create a custom QueryEntity based on the required POJO types:
https://ignite.apache.org/docs/latest/SQL/sql-api#query-entities
Or you can use special annotations in your POJO object:
https://ignite.apache.org/docs/latest/SQL/sql-api#querysqlfield-annotation
2)Using SQL syntax, you must set the correct key and value types using the following properties:
CREATE TABLE IF NOT EXISTS Person (
id int,
city_id int,
name varchar,
age int,
company varchar,
PRIMARY KEY (id, city_id)
) WITH "template=partitioned,backups=1,affinity_key=city_id, key_type=com.test.PersonKey, value_type=com.test.MyPerson"
https://ignite.apache.org/docs/latest/sql-reference/ddl
Related
Using EF Core 2.2.6 and Pomelo.EntityFrameworkCore.MySql 2.2.6 (with MySqlConnector 0.59.2)). I have a model for UserData:
public class UserData
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public ulong ID { get; private set; }
[Required]
public Dictionary<string, InventoryItem> Inventory { get; set; }
public UserData()
{
Data = new Dictionary<string, string>();
}
}
I have a REST method that can be called that will add items to the user inventory:
using (var transaction = context.Database.BeginTransaction())
{
UserData data = await context.UserData.FindAsync(userId);
// there is code here to detect duplicate entries/etc, but I've removed it for brevity
foreach (var item in items) data.Inventory.Add(item.ItemId, item);
context.UserData.Update(data);
await context.SaveChangesAsync();
transaction.Commit();
}
If two or more calls to this method are made with the same user id then I get concurrent accesses (despite the transaction). This causes the data to sometimes be incorrect. For example, if the inventory is empty and then two calls are made to add items simultaneously (item A and item B), sometimes the database will only contain either A or B, and not both. From logging it appears that it is possible for EF to read from the database while the other read/write is still occurring, causing the code to have the incorrect state of the inventory for when it tries to write back to the db. So I tried marking the isolation level as serializable.
using (var transaction = context.Database.BeginTransaction(System.Data.IsolationLevel.Serializable))
Now I sometimes see an exception:
MySql.Data.MySqlClient.MySqlException (0x80004005): Deadlock found when trying to get lock; try restarting transaction
I don't understand how this code could deadlock... Anyways, I tried to proceed by wrapping this whole thing in a try/catch, and retry:
public static async Task<ResponseError> AddUserItem(Controller controller, MyContext context, ulong userId, List<InventoryItem> items, int retry = 5)
{
ResponseError result = null;
try
{
using (var transaction = context.Database.BeginTransaction(System.Data.IsolationLevel.Serializable))
{
UserData data = await context.UserData.FindAsync(userId);
// there is code here to detect duplicate entries/etc, but I've removed it for brevity
foreach (var item in items) data.Inventory.Add(item.ItemId, item);
context.UserData.Update(data);
await context.SaveChangesAsync();
transaction.Commit();
}
}
catch (Exception e)
{
if (retry > 0)
{
await Task.Delay(SafeRandomGenerator(10, 500));
return await AddUserItem(controller, context, userId, items, retry--);
}
else
{
// store exception and return error
}
}
return result;
}
And now I am back to the data being sometimes correct, sometimes not. So I think the deadlock is another problem, but this is the only method accessing this data. So, I'm at a loss. Is there a simple way to read from the database (locking the row in the process) and then writing back (releasing the lock on write) using EF Core? I've looked at using concurrency tokens, but this seems overkill for what appears (on the surface to me) to be a trivial task.
I added logging for mysql connector as well as asp.net server and can see the following failure:
fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
=> RequestId:0HLUD39EILP3R:00000001 RequestPath:/client/AddUserItem => Server.Controllers.ClientController.AddUserItem (ServerSoftware)
Failed executing DbCommand (78ms) [Parameters=[#p1='?' (DbType = UInt64), #p0='?' (Size = 4000)], CommandType='Text', CommandTimeout='30']
UPDATE `UserData` SET `Inventory` = #p0
WHERE `ID` = #p1;
SELECT ROW_COUNT();
A total hack is to just delay the arrival of the queries by a bit. This works because the client is most likely to generate these calls on load. Normally back-to-back calls aren't expected, so spreading them out in time by delaying on arrival works. However, I'd rather find a correct approach, since this just makes it less likely to be an issue:
ResponseError result = null;
await Task.Delay(SafeRandomGenerator(100, 500));
using (var transaction = context.Database.BeginTransaction(System.Data.IsolationLevel.Serializable))
// etc
This isn't a good answer, because it isn't what I wanted to do, but I'll post it here as it did solve my problem. My problem was that I was trying to read the database row, modify it in asp.net, and then write it back, all within a single transaction and while avoiding deadlocks. The backing field is JSON type, and MySQL provides some JSON functions to help modify that JSON directly in the database. This required me to write SQL statements directly instead of using EF, but it did work.
The first trick was to ensure I could create the row if it didn't exist, without requiring a transaction and lock.
INSERT INTO UserData VALUES ({0},'{{}}','{{}}') ON DUPLICATE KEY UPDATE ID = {0};
I used JSON_REMOVE to delete keys from the JSON field:
UPDATE UserData as S set S.Inventory = JSON_REMOVE(S.Inventory,{1}) WHERE S.ID = {0};
and JSON_SET to add/modify entries:
UPDATE UserData as S set S.Inventory = JSON_SET(S.Inventory,{1},CAST({2} as JSON)) WHERE S.ID = {0};
Note, if you're using EF Core and want to call this using FromSql then you need to return the entity as part of your SQL statement. So you'll need to add something like this to each SQL statement:
SELECT * from UserData where ID = {0} LIMIT 1;
Here is a full working example as an extension method:
public static async Task<UserData> FindOrCreateAsync(this IQueryable<UserData> table, ulong userId)
{
string sql = "INSERT INTO UserData VALUES ({0},'{{}}','{{}}') ON DUPLICATE KEY UPDATE ID = {0}; SELECT * FROM UserData WHERE ID={0} LIMIT 1;";
return await table.FromSql(sql, userId).SingleOrDefaultAsync();
}
public static async Task<UserData> JsonRemoveInventory(this DbSet<UserData> table, ulong userId, string key)
{
if (!key.StartsWith("$.")) key = $"$.\"{key}\"";
string sql = "UPDATE UserData as S set S.Inventory = JSON_REMOVE(S.Inventory,{1}) WHERE S.ID = {0}; SELECT * from UserData where ID = {0} LIMIT 1;";
return await table.AsNoTracking().FromSql(sql, userId, key).SingleOrDefaultAsync();
}
Usage:
var data = await context.UserData.FindOrCreateAsync(userId);
await context.UserData.JsonRemoveInventory(userId, itemId);
I'm seeing "caching" behavior with database (MySQL 5) records. I can't seem to see the new data application side w/o logging in/out or restarting the app server (Glassfish 3). This is the only place in the application where db records are "stuck." I'm guessing I'm missing something with JPA persistence.
I've attempted changing db records by hand, there's still some sort of caching mechanism in place "helping" me.
This is editFile() method that saves new data.
After I fire this, I see the data updated in the db as expected.
this.file is the class level property that the view uses to show file data. It shows old data. I attempt to move db data back in to it after I've fired my UPDATE queries with the filesList setter: this.setFilesList(newFiles);
When the application reads it back out though, GlassFish seems to resond with requests for this data w/ old data.
public void editFile(Map<String, String> params) {
// update file1 record
File1 thisFile = new File1();
thisFile.setFileId(Integer.parseInt(params.get("reload-form:fileID")));
thisFile.setTitle(params.get("reload-form:input-small-name"));
thisFile.setTitle_friendly(params.get("reload-form:input-small-title-friendly"));
this.filesFacade.updateFileRecord(thisFile);
//update files_to_categories record
int thisFileKeywordID = Integer.parseInt(params.get("reload-form:select0"));
this.filesToCategoriesFacade.updateFilesToCategoriesRecords(thisFile.getFileId(), thisFileKeywordID);
this.file = this.filesFacade.findFileByID(thisFile.getFileId());
List<File1> newFiles = (List<File1>)this.filesFacade.findAllByRange(low, high);
this.setFilesList(newFiles);
}
Facades
My Facades are firing native SQL to update each of those DB tables. When I check the DB after they fire, the data is going in, that part is happening as I expect and hope.
File1
public int updateFileRecord(File1 file){
String title = file.getTitle();
String title_titleFriendly = file.getTitle_friendly();
int fileID = file.getFileId();
int result = 0;
Query q = this.em.createNativeQuery("UPDATE file1 set title = ?1, title_friendly = ?2 where file_id = ?3");
q.setParameter(1, title);
q.setParameter(2, title_titleFriendly);
q.setParameter(3, fileID);
result = q.executeUpdate();
return result;
}
FilesToCategories
public int updateFilesToCategoriesRecords(int fileId, int keywordID){
Query q = this.em.createNativeQuery("UPDATE files_to_categories set categories = ?1 where file1 = ?2");
q.setParameter(1, keywordID);
q.setParameter(2, fileId);
return q.executeUpdate();
}
How do I un-cache?
Thanks again for looking.
I don't think caching is the Problem, I think it's transactions.
em.getTransaction().begin();
Query q = this.em.createNativeQuery("UPDATE file1 set title = ?1, title_friendly = ?2 where file_id = ?3");
q.setParameter(1, title);
q.setParameter(2, title_titleFriendly);
q.setParameter(3, fileID);
result = q.executeUpdate();
em.getTransaction().commit();
I recommend to surrond your Writings to the DB with Transactions to get them persisted. Unless you commit requests may return results without the changes.
Ok, JTA does the Transactionmanagement.
Why are you doing this, when you are using JPA.
public int updateFileRecord(File1 file){
String title = file.getTitle();
String title_titleFriendly = file.getTitle_friendly();
int fileID = file.getFileId();
int result = 0;
Query q = this.em.createNativeQuery("UPDATE file1 set title = ?1, title_friendly = ?2 where file_id = ?3");
q.setParameter(1, title);
q.setParameter(2, title_titleFriendly);
q.setParameter(3, fileID);
result = q.executeUpdate();
return result;
}
This should work and update the internal State that comes with JPA
public int updateFileRecord(File1 file){
em.persist(file);
}
#daniel & #Tiny got me going on this one, thanks again guys.
I wanted to point out that I used the .merge() method out of the Entity Manager class.
It's important to note that for .merge() to UPDATE the record instead of INSERTing a new one; that the object you're submitting to .merge() must include all properties respective of the fields in the database table (that your DAO knows about) or you will INSERT new database records.
public void updateFileRecord(File1 file){
em.merge(file);
}
I have some MySQL scripts that are needed for recreating a database. They work fine when I execute them on the command line using the mysql command.
Now I wrote a Java class that should execute these scripts using a JDBC connection to the MySQL database.
One line in a "create table"-statement in the script is:
registration_date DATETIME DEFAULT CURRENT_TIMESTAMP
This line however won't be executed using the JDBC-MySQL connection. I get the error:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Invalid default value for 'registration_date'
The relevant method is shown below. sqlScriptPathpoints to the folder containing the sql scripts. The connectionString has this content: "jdbc:mysql://localhost:3306/testDb?useUnicode=yes&characterEncoding=UTF-8&allowMultiQueries=true"
public static void recreate(String connectionString, String dbUser, String dbPass, String sqlScriptPath) throws Exception {
// Find and filter sql scripts
File file = new File(sqlScriptPath);
File[] scripts = file.listFiles(new FileFilter() {
#Override
public boolean accept(File file) {
return file.getName().endsWith(".sql");
}
});
List<File> scriptsList = Arrays.asList(scripts);
Collections.sort(scriptsList);
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection conn = DriverManager.getConnection(connectionString, dbUser, dbPass);
// Load each script and apply it
for (File f : scriptsList) {
System.out.println("Importing script: " + f);
List<String> lines = Files.readAllLines(Paths.get(f.getAbsolutePath()), Charset.forName("UTF-8"));
StringBuilder sb = new StringBuilder();
for (String line : lines) sb.append(line).append("\n");
String sqlStatement = sb.toString();
System.out.print(sqlStatement);
Statement st = conn.createStatement();
st.execute(sqlStatement);
st.close();
}
}
And the relevant part of the script:
CREATE TABLE user
(
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
username VARCHAR(255),
password VARCHAR(255),
age_group INT,
registration_date DATETIME DEFAULT CURRENT_TIMESTAMP
)
ENGINE = InnoDB
DEFAULT CHARSET = utf8;
What is the problem here?
I inherited a Java test harness for a MySQL database that was failing with this error on a datetime column defined as NOT NULL with no default defined. I added DEFAULT NOW() and it worked fine after that.
I am trying to perform IN search using JbdcTemplate in Spring. Here goes my code
#Override
public Map<String, List> dataRetriveForAsset(String type) {
List<Integer> interfaceIdList = new ArrayList<Integer>();
List<Integer> fileList = new ArrayList<Integer>();
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
String sql2 = "select interface_id from tbl_interface_asset where asset_id in ( :ids )";
//fileList is populated with a different query
Set<Integer> ids = new HashSet(Arrays.asList(new Integer[fileList.size()] ));
for(int i=0; i<fileList.size();i++)
{
ids.add(fileList.get(i));
}
MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("ids", ids);
interfaceIdList = jdbcTemplate.query(sql2,new ListMapper1(),parameters );
and the sql2 query part executes it throws the following error.
SEVERE: Servlet.service() for servlet [appServlet] in context with path [/iccdashboard] threw exception [Request processing failed; nested exception is org.springframework.dao.TransientDataAccessResourceException: PreparedStatementCallback; SQL [select interface_id from tbl_interface_asset where asset_id in ( :ids )]; Invalid argument value: java.io.NotSerializableException; nested exception is java.sql.SQLException: Invalid argument value: java.io.NotSerializableException] with root cause
java.io.NotSerializableException: org.springframework.jdbc.core.namedparam.MapSqlParameterSource
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at com.mysql.jdbc.PreparedStatement.setSerializableObject(PreparedStatement.java:4401)
at com.mysql.jdbc.PreparedStatement.setObject(PreparedStatement.java:4083)
at org.springframework.jdbc.core.StatementCreatorUtils.setValue(StatementCreatorUtils.java:351)
at org.springframework.jdbc.core.StatementCreatorUtils.setParameterValueInternal(StatementCreatorUtils.java:216)
at org.springframework.jdbc.core.StatementCreatorUtils.setParameterValue(StatementCreatorUtils.java:144)
But if I use NamedParameterJdbcTemplate, I am getting a BadSQLGrammarError because the 'ids' value my sql query goes emplty like below.
select interface_id from tbl_interface_asset where asset_id in ( )
java.io.NotSerializableException: org.springframework.jdbc.core.namedparam.MapSqlParameterSource
I was able to fix this problem by replacing my usage of
org.springframework.jdbc.core.JdbcTemplate
with the:
org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
I was using the MapSqlParameterSource class but using the standard template which may have been the problem.
But if I use NamedParameterJdbcTemplate, I am getting a BadSQLGrammarError because the 'ids' value my sql query goes empty like below.
Can you make the SQL generation conditional on whether or not there are entries in your IN collection?
if (!ids.isEmpty()) {
parameters.addValue("ids", ids);
}
I have the following JPA SqlResultSetMapping:
#SqlResultSetMappings({
#SqlResultSetMapping(name="GroupParticipantDTO",
columns={
#ColumnResult(name="gpId"),
#ColumnResult(name="gpRole"),
// #ColumnResult(name="gpRemarks")
}
)
Which is used like this:
StringBuilder sbQuery = new StringBuilder("Select ");
sbQuery.append(" gpId, ");
sbQuery.append(" gpRole, ");
// sbQuery.append(" gpRemarks ");
sbQuery.append(" FROM v_group_participants_with_details ");
Query query = em.createNativeQuery(sbQuery.toString(), "GroupParticipantDTO");
The view is like this:
DROP VIEW IF EXISTS `v_group_participants_with_details`;
CREATE VIEW `v_group_participants_with_details`
AS
SELECT
gp.id AS gpId,
gp.role AS gpRole,
gp.remarks AS gpRemarks
FROM GroupParticipation gp
;
The GroupParticipation table has the remarks column defined as LONGTEXT (I'm using Mysql 5.x)
Now for the problem:
When the remarks field is commented out from the query everything works perfectly, but if I try to include the remarks field in the query, I get the following error:
javax.persistence.PersistenceException: org.hibernate.MappingException:
No Dialect mapping for JDBC type: -1
at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException
(AbstractEntityManagerImpl.java:614)
at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:76)
What gives? How can I get a LONGTEXT column from a native query?
This problem is reported in HHH-1483 and HHH-3892. In short, Hibernate does not know, how to map a LONGVARCHAR column returned by a native query.
This problem is fixed in Hibernate 3.5.0+. For previous versions, a workaround would be to extend the MysqlDialect to register the correct Hibernate Type for a LONGVARCHAR:
import java.sql.Types;
import org.hibernate.Hibernate;
public class MyMySQL5Dialect extends org.hibernate.dialect.MySQL5Dialect {
public MyMySQL5Dialect() {
super();
// register additional hibernate types for default use in scalar sqlquery type auto detection
registerHibernateType(Types.LONGVARCHAR, Hibernate.TEXT.getName());
}
}