原文地址:http://loianegroner.com/2011/02/getting-started-with-ibatis-mybatis-xml-configuration/
这份教程将使用一个简单的Java项目来带您体验iBatis(MyBatis),并展示简单的插入、修改查询和删除操作。
准备工作
![](https://img-my.csdn.net/uploads/201204/08/1333885107_7932.png)
样例数据库
1 – Contact POJO
首先我们创建一个Contact类,包含id,name,phone和email这几个字段。2 - Contact.xml
Contact.xml是iBatis/MyBatis的SQL Map配置文件。我们将在这里编写SQL语句,并将这些SQL语句与对象的方法配置到一起,这里是ORM魔法的源泉。
- resultMap:iBatis中最强大也是最复杂的部分,它实现了Java对象到数据库表格的映射。
- insert:映射的insert语句
- update:映射的update语句
- select:映射的select语句
- delete:映射的delete语句
Result Map
Select语句
Delete语句
删除语句很简单,我们通过参数id来确认要删除的记录。Update语句
在update语句中参数的类型为Contact类,这意味着我们将传递一个类型为Contact的参数给DAO中的方法。注意SQL中的参数#{name}, #{phone}, #{email}和#{id}。SQL中所有的参数名必须和Contact的属性名一致,否则iBatis/MyBatis将无法完成映射。
Insert语句
3 - Mapper配置文件
- Configuration
- properties
- settings
- typeAliases
- typeHandlers
- objectFactory
- plugins
- environments
- environment
- transactionManager
- dataSource
- environment
- mappers
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<typeAlias alias="Contact" type="com.loiane.model.Contact"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/blog"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/loiane/data/Contact.xml"/>
</mappers>
</configuration>
下面我们来看看这些配置:
TypeAliases
Environments
Transaction Manager
JDBC:直接使用JDBC提供的commit和rollback来实现事务,依赖于从dataSource中获得的连接来控制食物的范围。MANAGED:这种配置相当于什么也不做。它从不提交、回滚一个连接。相反,它通过容器(例如:Spring或其他JavaEE容器)来管理事务。默认它是不关闭连接的。然而,有些容器默认并不是这样,因此需要手动来进行配置,将closeConnection属性设为false即可。
在本例中,我们将使用JDBC。
DataSource
dataSource元素用于用于配置使用标准JDBC接口的数据源。
- driver – This is the fully qualified Java class of the JDBC driver (NOT of the DataSource class ifyour driver includes one).
- url – This is the JDBC URL for your database instance.
- username – The database username to log in with.
- password – The database password to log in with.
4 – MyBatisConnectionFactory
每一个MyBatis应用的核心都是一个SqlSessionFactory。SqlSessionFactory对象可以通过SqlSessionFactoryBuilder获得。SqlSessionFactoryBuilder可以解析XML配置文件或已有的SqlSessionFactory对象来生成相应的SqlSessionFactory。package com.loiane.dao; import java.io.FileNotFoundException; import java.io.IOException; import java.io.Reader; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; public class MyBatisConnectionFactory { private static SqlSessionFactory sqlSessionFactory; static { try { String resource = "SqlMapConfig.xml"; Reader reader = Resources.getResourceAsReader(resource); if (sqlSessionFactory == null) { sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); } } catch (FileNotFoundException fileNotFoundException) { fileNotFoundException.printStackTrace(); } catch (IOException iOException) { iOException.printStackTrace(); } } public static SqlSessionFactory getSqlSessionFactory() { return sqlSessionFactory; } }
5 – ContactDAO
现在我们已经准备好了所需的一切,下面来创建DAO。为了调用sql语句,我们将通过命名空间和SQL语句的id来调用。package com.loiane.dao; import java.util.List; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import com.loiane.model.Contact; public class ContactDAO { private SqlSessionFactory sqlSessionFactory; public ContactDAO(){ sqlSessionFactory = MyBatisConnectionFactory.getSqlSessionFactory(); } /** * Returns the list of all Contact instances from the database. * @return the list of all Contact instances from the database. */ @SuppressWarnings("unchecked") public List<Contact> selectAll(){ SqlSession session = sqlSessionFactory.openSession(); try { List<Contact> list = session.selectList("Contact.getAll"); return list; } finally { session.close(); } } /** * Returns a Contact instance from the database. * @param id primary key value used for lookup. * @return A Contact instance with a primary key value equals to pk. null if there is no matching row. */ public Contact selectById(int id){ SqlSession session = sqlSessionFactory.openSession(); try { Contact contact = (Contact) session.selectOne("Contact.getById",id); return contact; } finally { session.close(); } } /** * Updates an instance of Contact in the database. * @param contact the instance to be updated. */ public void update(Contact contact){ SqlSession session = sqlSessionFactory.openSession(); try { session.update("Contact.update", contact); session.commit(); } finally { session.close(); } } /** * Insert an instance of Contact into the database. * @param contact the instance to be persisted. */ public void insert(Contact contact){ SqlSession session = sqlSessionFactory.openSession(); try { session.insert("Contact.insert", contact); session.commit(); } finally { session.close(); } } /** * Delete an instance of Contact from the database. * @param id primary key value of the instance to be deleted. */ public void delete(int id){ SqlSession session = sqlSessionFactory.openSession(); try { session.delete("Contact.deleteById", id); session.commit(); } finally { session.close(); } } }
下载
您若想了解更多有关MyBatis的知识,请您下载MyBatis的用户手册,那里拥有您所需的关于MyBatis一切。所有带引号的句子都来自MyBatis用户手册。在实现这个样例工程的过程中我也经常查阅那个手册。我同时还创建了一个测试类。您若想获得整个样例工程的源码,可以从github上下载:https://github.com/loiane/ibatis-helloworld
您若要下载zip格式的源码,只需点击下载,如下图所示:
后面的文章我将展示MyBatis更多的属性:)
coding快乐!
本文原文:
This tutorial will walk you through how to setupiBatis(MyBatis) in a simple Java project and will present examples using simple insert, update, select and delete statements.
Pre-Requisites
For this tutorial I am using:
IDE:Eclipse(you can use your favorite one)
DataBase:MySQL
Libs/jars:Mybatis,MySQLconector andJUnit(for testing)
This is how your project should look like:
Sample Database
Please run this script into your database before getting started with the project implementation:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
DROP
TABLE
IF EXISTS `blog`.`contact`;
CREATE
TABLE
`blog`.`contact` (
`CONTACT_ID`
int
(11)
NOT
NULL
AUTO_INCREMENT,
`CONTACT_EMAIL`
varchar
(255)
NOT
NULL
,
`CONTACT_NAME`
varchar
(255)
NOT
NULL
,
`CONTACT_PHONE`
varchar
(255)
NOT
NULL
,
PRIMARY
KEY
(`CONTACT_ID`)
)
ENGINE=InnoDB;
insert
into
CONTACT (CONTACT_NAME, CONTACT_PHONE, CONTACT_EMAIL)
values
(
'Contact0'
,
'(000) 000-0000'
,
'contact0@loianetest.com'
);
insert
into
CONTACT (CONTACT_NAME, CONTACT_PHONE, CONTACT_EMAIL)
values
(
'Contact1'
,
'(000) 000-0000'
,
'contact1@loianetest.com'
);
insert
into
CONTACT (CONTACT_NAME, CONTACT_PHONE, CONTACT_EMAIL)
values
(
'Contact2'
,
'(000) 000-0000'
,
'contact2@loianetest.com'
);
insert
into
CONTACT (CONTACT_NAME, CONTACT_PHONE, CONTACT_EMAIL)
values
(
'Contact3'
,
'(000) 000-0000'
,
'contact3@loianetest.com'
);
insert
into
CONTACT (CONTACT_NAME, CONTACT_PHONE, CONTACT_EMAIL)
values
(
'Contact4'
,
'(000) 000-0000'
,
'contact4@loianetest.com'
);
insert
into
CONTACT (CONTACT_NAME, CONTACT_PHONE, CONTACT_EMAIL)
values
(
'Contact5'
,
'(000) 000-0000'
,
'contact5@loianetest.com'
);
insert
into
CONTACT (CONTACT_NAME, CONTACT_PHONE, CONTACT_EMAIL)
values
(
'Contact6'
,
'(000) 000-0000'
,
'contact6@loianetest.com'
);
insert
into
CONTACT (CONTACT_NAME, CONTACT_PHONE, CONTACT_EMAIL)
values
(
'Contact7'
,
'(000) 000-0000'
,
'contact7@loianetest.com'
);
insert
into
CONTACT (CONTACT_NAME, CONTACT_PHONE, CONTACT_EMAIL)
values
(
'Contact8'
,
'(000) 000-0000'
,
'contact8@loianetest.com'
);
insert
into
CONTACT (CONTACT_NAME, CONTACT_PHONE, CONTACT_EMAIL)
values
(
'Contact9'
,
'(000) 000-0000'
,
'contact9@loianetest.com'
);
insert
into
CONTACT (CONTACT_NAME, CONTACT_PHONE, CONTACT_EMAIL)
values
(
'Contact10'
,
'(000) 000-0000'
,
'contact10@loianetest.com'
);
insert
into
CONTACT (CONTACT_NAME, CONTACT_PHONE, CONTACT_EMAIL)
values
(
'Contact11'
,
'(000) 000-0000'
,
'contact11@loianetest.com'
);
insert
into
CONTACT (CONTACT_NAME, CONTACT_PHONE, CONTACT_EMAIL)
values
(
'Contact12'
,
'(000) 000-0000'
,
'contact12@loianetest.com'
);
insert
into
CONTACT (CONTACT_NAME, CONTACT_PHONE, CONTACT_EMAIL)
values
(
'Contact13'
,
'(000) 000-0000'
,
'contact13@loianetest.com'
);
insert
into
CONTACT (CONTACT_NAME, CONTACT_PHONE, CONTACT_EMAIL)
values
(
'Contact14'
,
'(000) 000-0000'
,
'contact14@loianetest.com'
);
insert
into
CONTACT (CONTACT_NAME, CONTACT_PHONE, CONTACT_EMAIL)
values
(
'Contact15'
,
'(000) 000-0000'
,
'contact15@loianetest.com'
);
insert
into
CONTACT (CONTACT_NAME, CONTACT_PHONE, CONTACT_EMAIL)
values
(
'Contact16'
,
'(000) 000-0000'
,
'contact16@loianetest.com'
);
insert
into
CONTACT (CONTACT_NAME, CONTACT_PHONE, CONTACT_EMAIL)
values
(
'Contact17'
,
'(000) 000-0000'
,
'contact17@loianetest.com'
);
insert
into
CONTACT (CONTACT_NAME, CONTACT_PHONE, CONTACT_EMAIL)
values
(
'Contact18'
,
'(000) 000-0000'
,
'contact18@loianetest.com'
);
insert
into
CONTACT (CONTACT_NAME, CONTACT_PHONE, CONTACT_EMAIL)
values
(
'Contact19'
,
'(000) 000-0000'
,
'contact19@loianetest.com'
);
|
1 – Contact POJO
We will create a POJO class first to respresent a contact with id, name, phone number and email address:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
package
com.loiane.model;
public
class
Contact {
private
int
id;
private
String name;
private
String phone;
private
String email;
public
Contact(
int
id, String name, String phone, String email) {
super
();
this
.id = id;
this
.name = name;
this
.phone = phone;
this
.email = email;
}
public
Contact() {}
//getters and setters
}
|
2 – Contact.xml
This is the iBatis/myBatis SQL map configuration file for Contact class. We are going to write all the SQL queries, map a query to object in this file – here is where all the magic happens!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<
mapper
namespace
=
"Contact"
>
<
resultMap
id
=
"result"
type
=
"Contact"
>
<
result
property
=
"id"
column
=
"CONTACT_ID"
/>
<
result
property
=
"name"
column
=
"CONTACT_NAME"
/>
<
result
property
=
"phone"
column
=
"CONTACT_PHONE"
/>
<
result
property
=
"email"
column
=
"CONTACT_EMAIL"
/>
</
resultMap
>
<
select
id
=
"getAll"
resultMap
=
"result"
>
SELECT * FROM CONTACT
</
select
>
<
select
id
=
"getById"
parameterType
=
"int"
resultMap
=
"result"
>
SELECT * FROM CONTACT WHERE CONTACT_ID = #{id}
</
select
>
<
delete
id
=
"deleteById"
parameterType
=
"int"
>
DELETE from CONTACT WHERE CONTACT_ID = #{id};
</
delete
>
<
insert
id
=
"insert"
parameterType
=
"Contact"
>
INSERT INTO CONTACT (CONTACT_EMAIL, CONTACT_NAME, CONTACT_PHONE)
VALUES (#{name}, #{phone}, #{email});
<
selectKey
keyProperty
=
"id"
resultType
=
"int"
order
=
"AFTER"
>
select last_insert_id() as id
</
selectKey
>
</
insert
>
<
update
id
=
"update"
parameterType
=
"Contact"
>
UPDATE CONTACT
SET
CONTACT_EMAIL = #{email},
CONTACT_NAME = #{name},
CONTACT_PHONE = #{phone}
WHERE CONTACT_ID = #{id};
</
update
>
</
mapper
>
|
What this file contains:
- resultMap– The most complicated and powerful element that describes how to load yourobjects from the database result sets.
- insert– A mapped INSERT statement.
- update– A mapped UPDATE statement.
- delete– A mapped DELEETE statement.
- select– A mapped SELECT statement.
Result Map
The resultMap element is the most important and powerful element in MyBatis. It’s what allows you todo away with 90% of the code that JDBC requires to retrieve data from ResultSets, and in some casesallows you to do things that JDBC does not even support. In fact, to write the equivalent code forsomething like a join mapping for a complex statement could probably span thousands of lines of code.The design of the ResultMaps is such that simple statements don’t require explicit result mappings at all,and more complex statements require no more than is absolutely necessary to describe therelationships.
In this example, the name of the table column is different from the Contact class. That is why we have to map the column with the class property. If the column name is the same as the property, you do not need to use thecolumn=”"option in the result map.
And remember that TypeAliases are your friend. Use them so that you don’t have to keep typing the fully qualified path of your class out. – we are going to set it in the myBatis main configuration file.
Select statment
The first select statment in this example is called “getAll“, and it means we are going to use this id to call the statment in DAO class. The other option we set is the resultMap, which we mapped to contact class, and it means the statment is going to return a list of contacts (List).
The second select statment in this example is called “getById“. We set a option called parameter of type int (or Integer) and it returns a object of type Contact. Notice the parameter notation#{id}. This tells MyBatis to create a PreparedStatement parameter. With JDBC, such a parameter would be identified by a “?” in SQL passed to a new PreparedStatement.
Delete Statment
The delete statment is also very simple. We set a parameter type called id (same thing asgetByIdstatment) so we can filter what it is going to be deleted.
Update Statment
In the update statement we ser a parameter of type Contact, which means we are going to pass a contact object as parameter to the update method in DAO class. Note the parameter notation #{name}, #{phone}, #{email} and #{id}. All the parameters must have the same name as contact properties, otherwise myBatis will not be able to map the object-parameters.
Insert Statment
Insert is a little bit more rich in that it has a few extra attributes and sub-elements that allow it to deal with key generation in a number of ways. First, if your database supports auto-generated key fields (e.g. MySQL and SQL Server), then you can simply set useGeneratedKeys=”true” and set the keyProperty to the target property and you’re done.
MyBatis has another way to deal with key generation for databases that don’t support auto-generated column types, or perhaps don’t yet support the JDBC driver support for auto-generated keys.
In this example, we are going to set manually the generated id in the object with theselectKeyoption. In this example, theselectKeywould be run after the insert statment and with thelast_insert_id() function we will get the last generated key (of type int) and set it to the id property.
3 – Mapper Configuration File
The MyBatis XML configuration file contains settings and properties that have a dramatic effect on howMyBatis behaves. The high level structure of the document is as follows:
- Configuration
- properties
- settings
- typeAliases
- typeHandlers
- objectFactory
- plugins
- environments
- environment
- transactionManager
- dataSource
- environment
- mappers
Hint: you have to follow the order above, otherwise you will get an exception.
The SqlMapConfig.xml from our project:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
<
configuration
>
<
typeAliases
>
<
typeAlias
alias
=
"Contact"
type
=
"com.loiane.model.Contact"
/>
</
typeAliases
>
<
environments
default
=
"development"
>
<
environment
id
=
"development"
>
<
transactionManager
type
=
"JDBC"
/>
<
dataSource
type
=
"POOLED"
>
<
property
name
=
"driver"
value
=
"com.mysql.jdbc.Driver"
/>
<
property
name
=
"username"
value
=
"root"
/>
<
property
name
=
"password"
value
=
"root"
/>
</
dataSource
>
</
environment
>
</
environments
>
<
mappers
>
<
mapper
resource
=
"com/loiane/data/Contact.xml"
/>
</
mappers
>
</
configuration
>
|
Let’s take a look at the configuration properties we are using.
Type Aliases
A type alias is simply a shorter name for a Java type. It’s only relevant to the XML configuration andsimply exists to reduce redundant typing of fully qualified classnames.
Remember we used Contact as type in the resultMap property in Contact.xml ()? This is a great help!
Environments
MyBatis can be configured with multiple environments. This helps you to apply your SQL Maps to multiple databases for any number of reasons. For example, you might have a different configuration for your Development, Test and Production environments. Or, you may have multiple production databases that share the same schema, and you’d like to use the same SQL maps for both. There are many use cases.
One important thing to remember though: While you can configure multiple environments, you can only choose ONE per SqlSessionFactory instance.
The default environment and the environment IDs are self explanatory. Name them whatever you like, just make sure the default matches one of them.
Transaction Manager
There are two TransactionManager types (i.e. type=”[JDBC|MANAGED]”) that are included withMyBatis:
JDBC – This configuration simply makes use of the JDBC commit and rollback facilities directly. It relies on the connection retrieved from the dataSource to manage the scope of the transaction. MANAGED – This configuration simply does almost nothing. It never commits, or rolls back a connection. Instead, it lets the container manage the full lifecycle of the transaction (e.g. Spring or a JEE Application Server context). By default it does close the connection. However, some containers don’t expect this, and thus if you need to stop it from closing the connection, set the closeConnection property to false.
In this example we are going to use JDBC.
Data Source
The dataSource element configures the source of JDBC Connection objects using the standard JDBC DataSource interface.
- driver – This is the fully qualified Java class of the JDBC driver (NOT of the DataSource class ifyour driver includes one).
- url – This is the JDBC URL for your database instance.
- username – The database username to log in with.
- password – The database password to log in with.
4 – MyBatisConnectionFactory
Every MyBatis application centers around an instance of SqlSessionFactory. A SqlSessionFactory instance can be acquired by using the SqlSessionFactoryBuilder. SqlSessionFactoryBuilder can build a SqlSessionFactory instance from an XML configuration file, of from a custom prepared instance of the Configuration class.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
package
com.loiane.dao;
import
java.io.FileNotFoundException;
import
java.io.IOException;
import
java.io.Reader;
import
org.apache.ibatis.io.Resources;
import
org.apache.ibatis.session.SqlSessionFactory;
import
org.apache.ibatis.session.SqlSessionFactoryBuilder;
public
class
MyBatisConnectionFactory {
private
static
SqlSessionFactory sqlSessionFactory;
static
{
try
{
String resource =
"SqlMapConfig.xml"
;
Reader reader = Resources.getResourceAsReader(resource);
if
(sqlSessionFactory ==
null
) {
sqlSessionFactory =
new
SqlSessionFactoryBuilder().build(reader);
}
}
catch
(FileNotFoundException fileNotFoundException) {
fileNotFoundException.printStackTrace();
}
catch
(IOException iOException) {
iOException.printStackTrace();
}
}
public
static
SqlSessionFactory getSqlSessionFactory() {
return
sqlSessionFactory;
}
}
|
5 – ContactDAO
Now that we set up everything needed, let’s create our DAO. To call the sql statments, we need to call the namespace and the name of the SQl statment as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
package
com.loiane.dao;
import
java.util.List;
import
org.apache.ibatis.session.SqlSession;
import
org.apache.ibatis.session.SqlSessionFactory;
import
com.loiane.model.Contact;
public
class
ContactDAO {
private
SqlSessionFactory sqlSessionFactory;
public
ContactDAO(){
sqlSessionFactory = MyBatisConnectionFactory.getSqlSessionFactory();
}
/**
* Returns the list of all Contact instances from the database.
* @return the list of all Contact instances from the database.
*/
@SuppressWarnings
(
"unchecked"
)
public
List<Contact> selectAll(){
SqlSession session = sqlSessionFactory.openSession();
try
{
List<Contact> list = session.selectList(
"Contact.getAll"
);
return
list;
}
finally
{
session.close();
}
}
/**
* Returns a Contact instance from the database.
* @param id primary key value used for lookup.
* @return A Contact instance with a primary key value equals to pk. null if there is no matching row.
*/
public
Contact selectById(
int
id){
SqlSession session = sqlSessionFactory.openSession();
try
{
Contact contact = (Contact) session.selectOne(
"Contact.getById"
,id);
return
contact;
}
finally
{
session.close();
}
}
/**
* Updates an instance of Contact in the database.
* @param contact the instance to be updated.
*/
public
void
update(Contact contact){
SqlSession session = sqlSessionFactory.openSession();
try
{
session.update(
"Contact.update"
, contact);
session.commit();
}
finally
{
session.close();
}
}
/**
* Insert an instance of Contact into the database.
* @param contact the instance to be persisted.
*/
public
void
insert(Contact contact){
SqlSession session = sqlSessionFactory.openSession();
try
{
session.insert(
"Contact.insert"
, contact);
session.commit();
}
finally
{
session.close();
}
}
/**
* Delete an instance of Contact from the database.
* @param id primary key value of the instance to be deleted.
*/
public
void
delete(
int
id){
SqlSession session = sqlSessionFactory.openSession();
try
{
session.delete(
"Contact.deleteById"
, id);
session.commit();
}
finally
{
session.close();
}
}
}
|
Download
If you want to learn more about the MyBatis configuration options, please read the User Guide. You will find everything you need there. All the quoted sentences are from the MyBatis 3 User Guid. I also used it as reference to implement this sample project.
I also created a TestCase class. If you want to download the complete sample project, you can get it from my GitHub account:https://github.com/loiane/ibatis-helloworld
If you want to download the zip file of the project, just click on download:
Next articles we are going to explore more iBatis/MyBatis options!
Happy Coding!