Create MySQL stored procedure using JPA Hibernate - java

I'm trying to create a stored procedure in a MySQL database using the contents of a text file:
USE myDatabase;
DROP PROCEDURE IF EXISTS myStoredProcedure;
DELIMITER $$
CREATE PROCEDURE myStoredProcedure
(
_description VARCHAR(50),
_value INT
)
BEGIN
INSERT INTO myTable
(
description,
value
) VALUES (
_description,
_value
);
SELECT
id,
description,
value
FROM myTable
WHERE id = LAST_INSERT_ID();
END;
$$
DELIMITER ;
I execute the SQL using a native query:
Query query = entityManager.createNativeQuery(queryText);
...
query.executeUpdate();
But it gets an error on the DROP PROCEDURE
I commented out the DROP PROCEDURE and then it gets an error on the DELIMITER
Basically, it gets an error on any line after the first semicolon.
It seems as if JPA hibernate is parsing my query and telling me there's a problem with it rather than passing the unadulterated text onto MySQL.
The sql runs in MySQL without error.
I can't find anything in Google about creating a stored procedure with JPA, only calling one.
Does anyone have any insight on what I might be doing wrong? Or if this is even possible.

This can be possible if you mention the following property in the url
spring.datasource.url=jdbc:mysql://localhost:3306/test?allowMultiQueries=true
The allowMultiQueries will instruct the driver to sent delimited queries to the database.
Please note that if you are using native queries be-aware of sql injection attack.
You dont need to put the delimiter(DELIMITER) explicitly.The sql statement
The following query works
SET myDatabase;
DROP PROCEDURE IF EXISTS myStoredProcedure;
CREATE PROCEDURE myStoredProcedure ( _description VARCHAR(50), _value INT )
BEGIN
INSERT INTO
myTable ( description, value )
VALUES ( _description, _value );
SELECT id, description, value
FROM myTable
WHERE id = LAST_INSERT_ID();
END;

Related

How to retrieve output param from Stored Procedure with Hibernate

I am trying to execute a Stored Procedure which updates a column and retrieves the filename from the same table after updating
StoredProcedure:
CREATE DEFINER=`test`#`%` PROCEDURE `update_count`(
IN in_testID VARCHAR(64),
OUT out_FileName VARCHAR(100),
OUT out_Message VARCHAR(100))
BEGIN
UPDATE files SET count=count+1 WHERE testID=in_testID;
SELECT FileName INTO out_FileName FROM files WHERE testID = in_testID;
SET out_Message = 'File updated uccessfully';
END
JavaCode to execute this StoredProcedure:
Query query = session.createSQLQuery("CALL update_count(:in_testID, #out_FileName, #out_Message)").addEntity(FilesBean.class)
.setParameter("in_testID",body.getTestId());
query.executeUpdate();
Updated the query.executeUpdate() with query.list(). But the line returning a error ResultSet is from UPDATE. No Data
I need to fix this with using the createSQLQuery
The easiest way to do that is return the out parameter as part of the returning parameters (relevant only if you have access to the store procedures).
just add a store procedure like the following one
create procedure myProcedure_only_in_prams (
in in_Id int)
begin
call myProcedure(in_id,#out_Id) ;
select #out_id
END;
after done that it quite simple to use it with Hibernate in the following way
Query query = session.createSQLQuery(
"CALL myProcedure_only_in_parms (:in_Id)")
.setParameter("in_id", 123);
List result = query.list();
The result contains the out parameter, if you want return multiply parameters you can add it by doing select #parm1,#parm2,... ,#parmn
Hope it helped

ROW_NUMBER() on informix DB shows BIGINT is not supported

I am trying to add row numbers to a sql query to get a return resultset, but the JDBC does not support BIGINT it says. I look up https://db.apache.org/derby/docs/10.9/ref/rreffuncrownumber.html and https://www.ibm.com/support/knowledgecenter/SSGU8G_11.50.0/com.ibm.jdbc_pg.doc/ids_jdbc_141.htm.
The code:
String query = new StringBuilder("SELECT ROW_NUMBER() OVER() AS id, * FROM "+tableName).toString();
Error:
[Informix JDBC Driver][Informix]The data type bigint is not supported for current client/server configuration.
The IBM solution tells you to use getBigSerial() to get the BIGINT after the insert. However, I want to find a way to be able to add some auto increment numbers when it queries the table without creating an actual column. Is there a way?
You can cast it to VARCHAR in the query.
You can cast that String into BigInteger in Java code if you use it for something more than present it to the client.
Casting is good:
String query = "SELECT CAST(ROW_NUMBER() OVER() AS INT) AS id, * FROM "+tableName;
I test it with my informix database and it works.

How to populate object property with value generated by Mysql Trigger in MyBatis Insert

I can't get the value back from function. It does an insert on a table and must return a number. The data is insert correctly, but the number returned is always null.
Mysql
create table driver_order (
id int(11) unsigned NOT NULL AUTO_INCREMENT,
area_start varchar(200),
area_end varchar(200),
order_number varchar(200),
create_user varchar(200),
primary key (id)
);
DELIMITER $$
CREATE TRIGGER seq_driver_order_number BEFORE INSERT ON driver_order
FOR each ROW
BEGIN
DECLARE seq_type INT(10);
SET seq_type = getUserNo(NEW.create_user);
SET NEW.order_number = getNextCommSequence("motor", seq_type);
END$$
DELIMITER ;
Mybatis
<insert id="insertOrder" useGeneratedKeys="true" keyProperty="id" parameterType="DriverOrder">
INSERT INTO
DRIVER_ORDER(ID,ORDER_NUMBER,AREA_START,AREA_END,CREATE_USER,CREATE_TIME)
VALUES
(#{id},
#{orderNumber,jdbcType=VARCHAR},
#{areaStart,jdbcType=VARCHAR},
#{areaEnd,jdbcType=VARCHAR},
#{createUser,jdbcType=VARCHAR},
now())
</insert>
The return Object all attributes have correctly value include id, except order_number which TRIGGER set value is return null.
Is there something wrong?
The problem is not with a trigger but how to make mybatis get value generated on mysql side during record insertion. Mybatis is rather simple tool in sense that you can't specify properties to columns mapping and everything else happens automagically.
Mybatis core is sql queries not properties-to-columns mappings like in hibernate for example. So mybatis only executes queries and simplifies setting parameters and construction objects from query result.
Nevertheless starting from version 3.2.6 you can use selectKey to get several values and set properties in the object being inserted. If you combine this with last_insert_id() you can get what you need. For your case it is done like this:
<insert id="insertOrder" parameterType="DriverOrder">
<selectKey keyProperty="id,orderNumber" keyColumn="ID,ORDER_NUMBER" order="AFTER" resultType="java.util.Map">
SELECT ID,ORDER_NUMBER FROM DRIVER_ORDER where ID = last_insert_id()
</selectKey>
INSERT INTO
DRIVER_ORDER(ID,ORDER_NUMBER,AREA_START,AREA_END,CREATE_USER,CREATE_TIME)
VALUES
(#{id},
#{orderNumber,jdbcType=VARCHAR},
#{areaStart,jdbcType=VARCHAR},
#{areaEnd,jdbcType=VARCHAR},
#{createUser,jdbcType=VARCHAR},
now())
</insert>

Mysql Procedure Containing Both select And Update Statement....How to call such procedure from Java

I have a table named notification
id BIGINT PK
subject VARCHAR(256)
send_to VARCHAR(50) //Email id to which notification sent
status TINYINT(1) default '0' //Indicates whether notification seen
or not by destination
Also I have a procedure to read a notification given below:
DELIMITER ##
DROP PROCEDURE wm_request_complaint_read ##
CREATE PROCEDURE wm_umis_db.wm_request_complaint_read (
IN p_id BIGINT, IN p_send_to CHAR(2)
)
BEGIN
select rc.subject, rc.details, rc.attach_file, rc.date, rc.type,
rc.sender_email
from notification rc
where rc.id = p_id AND rc.send_to=p_send_to ;
Update notification set status='1' where id=p_id AND send_to=p_send_to;
END ## DELIMITER ;
Above procedure contains both SELECT and UPDATE Statement
I am able to run above procedure from Mysql GUI tools...
but i want to run it from Java(I am using JDBC API)..
what code i should write....?
private static final String READ_COMPLAINT_OR_REQUEST="call
wm_request_complaint_read(?,?)";
conn=getConnection();
CallableStatement cstmt=conn.prepareCall(READ_COMPLAINT_OR_REQUEST);
cstmt.setLong(1, id);
cstmt.setString(2, sendTo);
ResultSet rset=cstmt.executeQuery();
OR
private static final String READ_COMPLAINT_OR_REQUEST="call
wm_request_complaint_read(?,?)";
conn=getConnection();
CallableStatement cstmt=conn.prepareCall(READ_COMPLAINT_OR_REQUEST);
cstmt.setLong(1, id);
cstmt.setString(2, sendTo);
cstmt.executeUpdate();
What the method does internally is not important for chosing the method to call. The important thing is if it returns something or not. Since your method does not return something, executeUpdate should be sufficient. Use executeQuery if your procedure returns a result set, and executeUpdate if it does not. In fact executeUpdate will throw an exeption if you call it on a procedure that would produce a result set.
See also http://download.oracle.com/javase/1.4.2/docs/api/java/sql/PreparedStatement.html#executeQuery()

Howto return ids on Inserts with Ibatis ( with RETURNING keyword )

I'm using iBatis/Java and Postgres 8.3.
When I do an insert in ibatis i need the id returned.
I use the following table for describing my question:
CREATE TABLE sometable ( id serial NOT NULL, somefield VARCHAR(10) );
The Sequence sometable_id_seq gets autogenerated by running the create statement.
At the moment i use the following sql map:
<insert id="insertValue" parameterClass="string" >
INSERT INTO sometable ( somefield ) VALUES ( #value# );
<selectKey keyProperty="id" resultClass="int">
SELECT last_value AS id FROM sometable_id_seq
</selectKey>
</insert>
It seems this is the ibatis way of retrieving the newly inserted id. Ibatis first runs a INSERT statement and afterwards it asks the sequence for the last id.
I have doubts that this will work with many concurrent inserts. ( discussed in this question )
I'd like to use the following statement with ibatis:
INSERT INTO sometable ( somefield ) VALUES ( #value# ) RETURNING id;
But when i try to use it within a <insert> sqlMap ibatis does not return the id. It seems to need the <selectKey> tag.
So here comes the question:
How can i use the above statement with ibatis?
The <selectKey> element is a child of the <insert> element and its content is executed before the main INSERT statement. You can use two approaches.
Fetch the key after you have inserted the record
This approach works depending on your driver. Threading can be a problem with this.
Fetching the key before inserting the record
This approach avoids threading problems but is more work. Example:
<insert id="insert">
<selectKey keyProperty="myId"
resultClass="int">
SELECT nextVal('my_id_seq')
</selectKey>
INSERT INTO my
(myId, foo, bar)
VALUES
(#myId#, #foo#, #bar#)
</insert>
On the Java side you can then do
Integer insertedId = (Integer) sqlMap.insert("insert", params)
This should give you the key selected from the my_id_seq sequence.
Here is simple example:
<statement id="addObject"
parameterClass="test.Object"
resultClass="int">
INSERT INTO objects(expression, meta, title,
usersid)
VALUES (#expression#, #meta#, #title#, #usersId#)
RETURNING id
</statement>
And in Java code:
Integer id = (Integer) executor.queryForObject("addObject", object);
object.setId(id);
This way more better than use :
It's simpler;
It have not requested to know sequence name (what usually hidden from postgresql developers).

Categories

Resources