mybatis - insert transaction - java

mybatis mapper code for insert:
<insert id="insert" parameterType="Shop" useGeneratedKeys="true">
insert into shop(email, pswd, nickname, mobile, city, create_date, status) values (#{email}, #{pswd}, #{nickname}, #{mobile}, #{city}, #{createDate}, #{status})
<selectKey keyProperty="id" order="AFTER" resultType="long">
select currval('shop_id_seq')
</selectKey>
</insert>
The database is postgresql 9.3.
My doubt is: without explicity transaction, when I retrieve the id from sequence with select currval('shop_id_seq'), is it possible to get the wrong value if other threads are also doing insert?
I thought it won't, because currval() function runs in context of current session, not global session, but I am not that sure.

According to PostgreSQL: Documentation: 9.3: Sequence Manipulation Functions, the sequence function currval:
Return the value most recently obtained by nextval for this sequence in the current session. (An error is reported if nextval has never been called for this sequence in this session.) Because this is returning a session-local value, it gives a predictable answer whether or not other sessions have executed nextval since the current session did.
So you will get the correct value. In another way, the sequences are non-transactional. Each session gets a distinct sequence value. The changes in the sequence can not be undone.

Related

Retrieve generated keys from multiple queries in single Spring JDBC Update

I am using a single Spring JDBC update to make an update to two tables in my Postgres database. My SQL query is as follows:
UPDATE accounts SET last_transaction_amount = :transaction_amount WHERE acct_num = :acct_num; INSERT INTO transactions (transaction_amout) VALUES (:transaction_amount);
Using NamedParameterJdbcTemplate#update, I have no issue executing this query and achieving the expected results.
The transactions table generates a sequential transaction identifier, and I want to return this to my application.
I've tried passing a GeneratedKeyHolder in the update call. This is returning the error "A result was returned when none was expected". Docs link.
I've tried passing a GeneratedKeyHolder and array of column names (new String[] {"transaction_id"}). This is returning the error that the column doesn't exist. Note this method call does work to return the transaction id when I only pass the INSERT query without the preceding UPDATE query. Docs link.
How can I retrieve the generated key? Thank you!
You seem to be looking for the RETURNING clause. Assuming that the serial number is called transaction_id:
INSERT INTO transactions (transaction_amout)
VALUES (:transaction_amount)
RETURNING transaction_id;

Mybatis selectKey not returning sequence value

I'm using the below insert query in mybatis. In ibatis, the same query returned seq_consumer_id.nextval to the calling method in java, and inserted the same into the consumer_id column. But in mybatis, return value of the method is always 1 (I'm assuming its the no of rows inserted), though consumer_id column is correctly updated from sequence. Can't we generate the key, insert it and return the same to java class in mybatis ?
<insert id="insertConsumer" parameterType="com.enrollment.vo.ConsumerVO">
<selectKey keyProperty="id" resultType="int" order="BEFORE">
select seq_consumer_id.nextval as id from dual
</selectKey>
insert into quotation_consumer (consumer_id, consumer_type, dob,
create_date, ENROLLMENT_INDICATOR, QUOTE_ID,IS_PRIMARY)
values(#{id},#{type.id}, #{birthdate, jdbcType=DATE}, default, #{enrollmentIndicator},
#{quoteId},#{isPrimary})
</insert>
Indeed the method returns the number of affected rows.
Sequence id is stored in ìd property of com.enrollment.vo.ConsumerVO passed as parameter.

Fire Sequence.nextval query using jdbctemplate in spring

Database : Oracle
I have table in which there are 10 columns and i want sequence next value when insert row and also use that sequence number which inserted.
Now i have searched and find that KeyHolder of spring is useful but restrict for only less than 8 field so i can't use that.
How can i fire "select MySequence.nextval from dual" query and get sequence using jdbctemplate(NamedParameterJDBCTemplate) ?
Is other way to achieve for get inserted sequence value ?.
Using a jdbctemplate you can just mention the sequence generator as a value, e.g.
jdbcTemplate.update("INSERT INTO TABLE (id, data) VALUES (MySequence.nextval, ?)", new Object[] { data });
A note regarding the sequence generation: for versions before Oracle 12c you should have a trigger which will increment the sequence for you. From 12c you can use the auto-increment feature.
You can achieve this by using JdbcTemplate like this :
final SqlRowSet sqlRowSet = jdbcTemplate.queryForRowSet(NEXT_VALUE_QUERY);
sqlRowSet.next();// mandatory to move the cursor
sqlRowSet.getLong(1);// the value of the nextval

HibernateTemplate Delete by condition that may include checking NULL

I am trying to write a DAO using Spring's HibernateTemplate that supports deletion from a table based on several conditions. For example, sample SQL:
Delete from Employee where Name='E01' AND Dept='D01' AND Address='ADR01';
I wrote the below code for this query:
session.createQuery("delete from Employee where name=? and dept=? and address=?")
.setParameter(0, name).setParameter(1, dept).setParameter(2, address)
.executeUpdate();
it works fine if all columns in where clause have some values. However, if I try to delete records which have "NULL" in their any column, then it does not work.
The generated SQL Query is always of the form:
Delete from Employee where Name=? AND Dept=? AND Address=?;
which of course cannot handle NULL comparison - SQL requires "IS NULL" for checking NULL and "=null" doesn't do the trick here. So when I pass dept as null in Java code, the generated SQL would be of the form:
Delete from Employee where Name='E01' AND Dept=null AND Address='ADR01';
This does not delete the records from DB which have NULL values in Dept column, as the correct condition would be "Dept IS NULL"; and "Dept=null" does not work! Is there anyway to compare NULL values in where clause without using a native query?
NOTE:
I do not want to use deleteAll(Collection) method of HibernateTemplate, as it requires fetching the records first and then deleting them - i.e. more than 1 SQL query. I want to achieve deletion using a single SQL query, without requiring to select first, or requiring native queries.
I am aware that Spring advices using SessionFactory now, but I am stuck with HibernateTemplate in existing code base.

Atomically fetch and increase sequence value in MySql

I convert the DB from Oracle to MySQL.
I'm using both Java & Hibernate.
When I used oracle I had the following method that gave me a brand new and unused sequence value:
protected int getSequenceNextValue() {
Session session = sessionFactory.getCurrentSession();
Query query = session.createSQLQuery("select MY_SEQUENCE.NEXTVAL from DUAL");
return ((BigDecimal) query.uniqueResult()).intValueExact();
}
And I'm trying to refactor this method to work on MySQL DB.
I have a table in MySQL that I use as a sequence (through Hibernate):
create table MY_SEQUENCE(
next_val int(10) NOT NULL
);
Is there any thread safe way to get a new value from this table and in the same transction to increase it?
For most cases I use the Hibernate Generator to generate a new sequence using this table, but in several cases I need to do it manually.
The best solution for me will be a refactoring of the method above, in such way that threads that querying the table at the same time will not fail, but will wait for each other.
Thanks...
Have a look at the InnoDB table type and FOR UPDATE. An example similar to what you describe is in the MySQL manual here http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html

Categories