Unlike Hibernate, MyBatis lets developers think in terms of SQL. Mybatis’ essential functionalities are:
- Automatic mapping between Java POJOs and table records.
- Easy construction of SQL statements.
We only want to write one SQL statement for each type of SQL. We don’t consider complex SQL statements such as SQL JOIN and UNION here. The structures of SQL statements are as follows;
-- SELECT
select
from
where
grouby
order by
-- INSERT
insert into
values
-- UPDATE
update
set
where
-- DELETE
delete from
where
One MyBatis SQL statement only allows one input parameter. We have two options for the input parameter. One solution is to use a big Java POJO. But we usually want to reuse Java domain objects for this. We need to add properties to such Java domain objects. Such properties are meaningless in the problem domain. They polute the domain objects.
Another solution is to use a Java map. We can use such a Java map like a JSON object. We can dynamically manipulate the Java map. And we can still use Java POJO for such as an input parameter. We can use Jackson ObjectMapper do a convertion beforehand.
We can refer to map values recursively for input paramter. For example,
key1.key2.key3
refer to key3
of key2
map of key1
map of the input
parameter map.
In foreach, collection can be something like entries
if entries
is a key
of the input parameter map.
In foreach, neither item attribute nor index attribute has a default value. They must be specified.
<foreach collection="campaigns" item="item" index="index" separator=",">
Tips
Parameter
For the following query:
<delete id="delete" parameterType="int">
delete from freight_house where id = #{id}
</delete>
Both of the following two approaches work. One is with a int paramter:
session.delete("delete", 28);
The other is is with a map:
Map map = new HashMap();
map.put("id" 28);
session.delete("delete", 28);
Transaction
JDBC does not have a method to start a transaction. MyBatis automatically rollback failed transactions. For example, the following code will neither delete row 3 nor row 4.
try(SqlSession s = Config.getSsf().openSession();) {
s.delete("FreightHouse.deleteTest", 3);
if (true) throw new RuntimeException();
s.delete("FreightHouse.deleteTest", 4);
s.commit();
}
SqlSession openSession()
does not have autocommit enabled.
Return Value
For the following query which contains two delete statemewnts, SqlSession.delete
returns the rows affected by the first delete statement.
<delete id="twoDeletes">
delete from freight_house where id = 888;
delete from freight_house where id = 5 or id = 6;
</delete>
For multiple SQL statements which update database, delete
, insert
and update
methods of SqlSession
return the rows affected by the first SQL statement. For
example, the row number affected by the insert SQL is returned.
<update id="update">
insert into category(name) values('golang');
update category set name = 'two' where id = 10000;
</update>
In the following list, any MyBatis statement in item 1 can contains any SQL statement in item 2.
- MyBatis insert, update and delete statements.
- SQL insert, update and delete statements.
White Spaces
For the following code, Mybatis will insert a while space between these two
if
s:
<if test="name != null and name != ''">and name like surr_with_p(#{name})</if><if test="typeId != null and typeId != ''">and type_id = #{typeId}</if>
List
MyBatis only accepts List
or native array. It does not accept Set
.
Null Tests
typeId != null and typeId != ''
is preferred over typeId != null
. If a SQL
statement containing such code is accessed from JS side and no type conversion
is done on Java side, it is very possible that typeId
is set to ''
even
typeId
is a integer on Java side. The reason is that empty string is
default value in many situations for JS.
In the following code, _parameter
checking can be avoided.
<select id="select">
<where>
<if test="_parameter != null and name != null and name != ''">
and name = #{name}
</if>
</where>
</select>
The following code works for a map input paramter. But it does not work a Java bean which does not have diameter property.
<if test="diameter != null and diameter != ''">
and diameter = #{diameter}
</if>
Java Generics
MyBatis does not ensure java generics. Java code:
public class Item {
// ...
}
public class Item_ extends Item {
// ...
}
public class Seller {
private List<Item_> items;
public List<Item_> getItems() {
return categories;
}
public void setItems(List<Item_> items) {
this.items = items;
}
}
XML:
<resultMap id="Item" type="Item">
</resultMap>
<select id="selectItems" resultMap="Item">
<!-- ... -->
</select>
MyBatis will happily return an items which is a list of Item
.
try-with-resources statement
The following code from Java API works:
try (SqlSession session = sqlSessionFactory.openSession()) {
// following 3 lines pseudocode for "doing some work"
session.insert(...);
session.update(...);
session.delete(...);
session.commit();
}
The reason is that the same link says
Most of the time you won’t have to call rollback(), as MyBatis will do that for you if you don’t call commit.
XML Escaping in SQL
>
can be processed correctly by Mybatis. But <
must be escaped as <
.
The reason is that <
starts a XML tag.
It is better to use XML character entity references as demanded by XML all the
time. So >
should be escaped as >
.