mybatis 3.0.2 试用小记
转自:http://www.blogjava.net/javaren/archive/2010/09/27/332226.html
以前用过一次ibatis2.x, 最近看到它改名了,并且已经升级到3.0.2, 就下载来尝试了下,下面简单说下, 希望能给想尝试不同ORM框架的朋友一些借鉴,我使用的是MySQL 5.1.x数据库。
首先, mybatis也有generator, 叫abator, 需要自己从svn上checkout出来:
svn co http://mybatis.googlecode.com/svn/sub-projects/generator/trunk/ abator
然后我是在eclipse里面使用的, 使用方法见eclipse的帮助文档,不过我再试用此工具时,生成的代码(DAO部分)还是2.x版本的,所以还要继续等官方升级呀。
首先建立包结构,mybatis 3.x文档上有建议的目录结构:
com.test.data 存放Mapper接口和XML,主配置文件
com.test.model 存放表映射实体类
com.test.service 是数据库操作类
mybatis 官方网站 www.mybatis.org
MySQL官方网站 www.mysql.com
需要用到的jar包: mybatis-3.0.1.jar和mysql-connector-java-5.1.10-bin.jar,其他可选包见mybatis发布包内optional目录
MySQL数据表test的 ddl :
CREATE TABLE test ( id int(11) NOT NULL AUTO_INCREMENT, txt1 varchar(100) CHARACTER SET utf8 DEFAULT NULL, txt2 varchar(100) CHARACTER SET utf8 DEFAULT NULL, PRIMARY KEY (id) ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
先来看主配置文件src/com/test/data/SqlMapConfig.xml内容:
xml version
=
"
1.0
"
encoding
=
"
UTF-8
"
?>
DOCTYPE configuration PUBLIC
"
-//ibatis.apache.org//DTD Config 3.0//EN
"
"
http://ibatis.apache.org/dtd/ibatis-3-config.dtd
"
>
<
configuration
>
<
properties resource
=
"
mysql.properties
"
/>
<
typeAliases
>
<
typeAlias type
=
"
com.test.model.Test
"
alias
=
"
Test
"
/>
typeAliases
>
<
environments
default
=
"
development
"
>
<
environment id
=
"
development
"
>
<
transactionManager type
=
"
JDBC
"
/>
<
dataSource type
=
"
POOLED
"
>
<
property name
=
"
driver
"
value
=
"
${driver}
"
/>
<
property name
=
"
url
"
value
=
"
${test.url}
"
/>
<
property name
=
"
username
"
value
=
"
${test.user}
"
/>
<
property name
=
"
password
"
value
=
"
${test.pass}
"
/>
dataSource
>
environment
>
environments
>
<
mappers
>
<
mapper resource
=
"
com/test/data/TestMapper.xml
"
/>
mappers
>
configuration
>
上面配置文件种引用了数据库配置属性文件src/mysql.properties,内容如下:
#################################### # Database Connectivity Properties #################################### driver
=
com.mysql.jdbc.Driver # test test.url
=
jdbc:mysql:
//
localhost:3306/test?useUnicode=true&characterEncoding=utf8&connectionCollation=utf8_general_ci
test.user
=
aa test.pass
=
1234
下面是数据库实体类 src/com/test/model/Test.java,内容如下:
package
com.test.model;
public
class
Test
implements
java.io.Serializable {
private
static
final
long
serialVersionUID
=
-
4081457458619235448L
;
private
int
id;
private
String
txt1; private String txt2;
public
void
setId(
int
id) {
this
.id
=
id; }
public
int
getId() {
return
this
.id; }
public
void
setTxt1(String txt) {
this
.txt1
=
txt; }
public
String getTxt1() {
return
this
.txt1; } public void setTxt2(String txt) { this.txt2 = txt; } public String getTxt2() { return this.txt2; } }
然后是对应的Mapper接口和XML文件,先看Mapper.xml文件 src/com/test/data/TestMapper.xml,注意,在该Mapper配置文件中,我并没有写resultMap属性,是因为我使用了#{属性名}方式,mybatis会自动去匹配实体类Test.java和字段之间的对应。
PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN" "http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd"> SELECT * FROM test WHERE id =#{id} SELECT * FROM test ORDER BY id INSERT INTO test (txt1,txt2) VALUES(#{txt1},#{txt2}) UPDATE test SET txt1=#{txt1},txt2=#{txt2} WHERE id=#{id} DELETE FROM test WHERE id=#{id}
下面是Mapper接口,为了方便进行单元测试和类型安全,新版mybatis建议使用接口来定义上面数据库的操作:src/com/test/data/TestMapper.java
package com.test.data; import java.util.List; import com.test.model.Test; public interface TestMapper { Test selectByid(int id); List selectByPage(); void insertTest(Test test); void updateTest(Test test); void deleteTestByid(int id); }
然后是session工厂:src/com/test/service/MyFactory.java
package
com.test.service;
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
MyFactory {
private
static
SqlSessionFactory sqlSessionFactory
=
null
;
static
{ String resource
=
"
com/test/data/SqlMapConfig.xml
"
; Reader reader
=
null
;
try
{ reader
=
Resources.getResourceAsReader(resource); }
catch
(IOException e) { System.err.println(e); } sqlSessionFactory
=
new
SqlSessionFactoryBuilder().build(reader); }
public
static
SqlSessionFactory sessionFactory() {
return
sqlSessionFactory; } }
操作类 src/com/test/service/TestService.java
package
com.test.service;
import
java.util.List;
import
org.apache.ibatis.session.RowBounds;
import
org.apache.ibatis.session.SqlSession;
import
com.test.data.TestMapper;
import
com.test.model.Test;
import
com.test.service.MyFactory;
public
class
TestService {
private
static
TestService instance
=
null
;
private
TestService() { }
public
static
TestService getInstance() {
if
(instance
==
null
) { instance
=
new
TestService(); }
return
instance; }
public
Test selectOneByid(
int
id) { Test t
=
null
; SqlSession session
=
MyFactory.sessionFactory().openSession();
try
{ TestMapper mapper
=
session.getMapper(TestMapper.
class
); t
=
mapper.selectByid(id); }
finally
{
if
(session
!=
null
) session.close(); }
return
t; }
@SuppressWarnings(
"
unchecked
"
)
public
List
<
Test
>
listByPage(
int
pg,
int
pz) { List
<
Test
>
tests
=
null
;
//
处理分页
int
offset
=
0
;
int
limit
=
0
;
if
(pg
>
0
) offset
=
(pg
-
1
)
*
pz;
else
offset
=
0
; limit
=
pz; SqlSession session
=
MyFactory.sessionFactory().openSession();
try
{ String mapper
=
"
com.test.data.TestMapper.selectByPage
"
;
//
分页处理,这里的分页是采用JDBC方式,对于数据量大的数据库,会有com.mysql.jdbc.PacketTooBigException错误,下面我会改进一下
RowBounds rowBounds
=
new
RowBounds(offset, limit); tests
=
session.selectList(mapper,
null
, rowBounds); }
finally
{
if
(session
!=
null
) session.close(); }
return
tests; }
public
int
insertOne(Test t) {
int
ret
=
0
; SqlSession session
=
MyFactory.sessionFactory().openSession();
try
{ TestMapper mapper
=
session.getMapper(TestMapper.
class
); mapper.insertTest(t); session.commit(); ret
=
1
; }
finally
{
if
(session
!=
null
) session.close(); }
return
ret; }
public
int
updateOne(Test t) {
int
ret
=
0
; SqlSession session
=
MyFactory.sessionFactory().openSession();
try
{ TestMapper mapper
=
session.getMapper(TestMapper.
class
); mapper.updateTest(t); session.commit(); ret
=
1
; }
finally
{
if
(session
!=
null
) session.close(); }
return
ret; }
public
int
deleteOneByid(
int
id) {
int
ret
=
0
; SqlSession session
=
MyFactory.sessionFactory().openSession();
try
{ TestMapper mapper
=
session.getMapper(TestMapper.
class
); mapper.deleteTestByid(id); session.commit(); ret
=
1
; }
finally
{
if
(session
!=
null
) session.close(); }
return
ret; } }
下面就来看下具体如何使用: src/MyTest.java
import
java.util.Iterator;
import
java.util.List;
import
com.test.model.Test;
import
com.test.service.TestService;
public
class
MyTest {
public
static
void
main(String[] args) {
//
select测试
int
id
=
23
; Test test
=
TestService.getInstance().selectOneByid(id); System.out.println(test.getId()
+
"
,
"
+
test.getTxt1()
+
"
,
"
+
test.getTxt2());
//
select分页测试
List
<
Test
>
tests
=
null
;
int
pg
=
1
;
//
我的数据库预置了100多万条记录,当pg比较大时,会抛出
com.mysql.jdbc.PacketTooBigException错误,也就是说mybatis把前面所有数据都取出来,然后再分页,儿不是利用MySQL数据库特有的分页机制limit ?,?
int
pz
=
10
;
//
每页取10条
tests
=
TestService.getInstance().listByPage(pg, pz);
if
(tests
!=
null
) { Iterator
<
Test
>
it
=
tests.iterator();
while
(it.hasNext()) { Test t
=
it.next(); System.out.println(t.getId()
+
"
,
"
+
t.getTxt1()
+
"
,
"
+
t.getTxt2()); } }
else
{ System.err.println(
"
没有数据
"
); }
//
insert测试
Test t1
=
new
Test(); t1.setTxt1(
"
hello1
"
); t1.setTxt2(
"
hello2
"
);
int
ret
=
TestService.getInstance().insertOne(t1); System.out.println(
"
写入
"
+
ret
+
"
条记录
"
);
//
update测试
Test t2
=
new
Test(); t2.setId(
23423
); t2.setTxt1(
"
hello3
"
); t2.setTxt2(
"
hello4
"
); ret
=
TestService.getInstance().updateOne(t1); System.out.println(
"
更新
"
+
ret
+
"
条记录
"
);
//
delete测试
id
=
2324
; ret
=
TestService.getInstance().deleteOneByid(id); System.out.println(
"
删除
"
+
ret
+
"
条记录
"
); } }
改进分页方式,我们利用MySQL独特的limit ?,?方式进行分页,这是效率最高的方式,有人说这么改会造成数据库移植的麻烦,但是进行移植(比如移植到Oracle)时很多SQL本身都要修改,所以这种麻烦微不足道,下面给出修改后的代码:
修改 src/com/test/data/TestMapper.xml
xml version
=
"
1.0
"
encoding
=
"
UTF-8
"
?>
DOCTYPE mapper PUBLIC
"
-//ibatis.apache.org//DTD Mapper 3.0//EN
"
"
http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd
"
>
<
mapper namespace
=
"
com.test.data.TestMapper
"
>
<
select id
=
"
selectByid
"
parameterType
=
"
int
"
resultType
=
"
Test
"
>
SELECT
*
FROM test WHERE id
=
#{id}
select
>
<
select id
=
"
selectByPage
"
resultType
=
"
Test
"
>
SELECT
*
FROM test ORDER BY id LIMIT #{offset},#{limit}
select
>
<
insert id
=
"
insertTest
"
parameterType
=
"
Test
"
>
INSERT INTO test (txt1,txt2) VALUES(#{txt1},#{txt2})
insert
>
<
update id
=
"
updateTest
"
parameterType
=
"
Test
"
>
UPDATE test SET txt1
=
#{txt1},txt2
=
#{txt2} WHERE id
=
#{id}
update
>
<
delete id
=
"
deleteTestByid
"
parameterType
=
"
int
"
>
DELETE FROM test WHERE id
=
#{id}
delete
>
mapper
>
相应Mapper接口也要修改:src/com/test/data/TestMapper.java
package
com.test.data;
import
java.util.List;
import
org.apache.ibatis.annotations.Param;
import
com.test.model.Test;
public
interface
TestMapper { Test selectByid(
int
id); List
<
Test
>
selectByPage(@Param(
"
offset
"
)
int
offset, @Param(
"
limit
"
)
int
limit); //这里修改了,使用了mybatis 3.x提供的注解的方法
void
insertTest(Test test);
void
updateTest(Test test);
void
deleteTestByid(
int
id); }
相应操作类修改:src/com/test/service/TestService.java
package
com.test.service;
import
java.util.List;
import
org.apache.ibatis.session.SqlSession;
import
com.test.data.TestMapper;
import
com.test.model.Test;
import
com.test.service.MyFactory;
public
class
TestService {
private
static
TestService instance
=
null
;
private
TestService() { }
public
static
TestService getInstance() {
if
(instance
==
null
) { instance
=
new
TestService(); }
return
instance; }
public
Test selectOneByid(
int
id) { Test t
=
null
; SqlSession session
=
MyFactory.sessionFactory().openSession();
try
{ TestMapper mapper
=
session.getMapper(TestMapper.
class
); t
=
mapper.selectByid(id); }
finally
{
if
(session
!=
null
) session.close(); }
return
t; }
public
List
<
Test
>
listByPage(
int
pg,
int
pz) { List
<
Test
>
tests
=
null
;
//
处理分页
int
offset
=
0
;
int
limit
=
0
;
if
(pg
>
0
) offset
=
(pg
-
1
)
*
pz;
else
offset
=
0
; limit
=
pz; SqlSession session
=
MyFactory.sessionFactory().openSession();
try
{
TestMapper mapper
=
session.getMapper(TestMapper.
class
); // 这里修改了,放弃RowBounds方式 tests
=
mapper.selectByPage(offset, limit); }
finally
{
if
(session
!=
null
) session.close(); }
return
tests; }
public
int
insertOne(Test t) {
int
ret
=
0
; SqlSession session
=
MyFactory.sessionFactory().openSession();
try
{ TestMapper mapper
=
session.getMapper(TestMapper.
class
); mapper.insertTest(t); session.commit(); ret
=
1
; }
finally
{
if
(session
!=
null
) session.close(); }
return
ret; }
public
int
updateOne(Test t) {
int
ret
=
0
; SqlSession session
=
MyFactory.sessionFactory().openSession();
try
{ TestMapper mapper
=
session.getMapper(TestMapper.
class
); mapper.updateTest(t); session.commit(); ret
=
1
; }
finally
{
if
(session
!=
null
) session.close(); }
return
ret; }
public
int
deleteOneByid(
int
id) {
int
ret
=
0
; SqlSession session
=
MyFactory.sessionFactory().openSession();
try
{ TestMapper mapper
=
session.getMapper(TestMapper.
class
); mapper.deleteTestByid(id); session.commit(); ret
=
1
; }
finally
{
if
(session
!=
null
) session.close(); }
return
ret; } }
好了,src/MyTest.java不用做修改,再次运行吧。
总结:mybatis 3.0.2 是个轻量级ORM框架,优点是使用简单,直接使用SQL来交互,占用内存少,速度比较快,缺点是分页处理采用JDBC自身的方式,效率低,另外,数据库间移植不方便,需要修改SQL,再就是没有类似hibernate的代码生成工具。
其它参考地址:
MyBatis google code : http://code.google.com/p/mybatis/
MyBatis运用心得 : http://chengjisihan.iteye.com/blog/752168
MyBatis3 SqlSessionFactory :http://www.cnblogs.com/archie2010/archive/2011/03/02/1968910.html
ibatis教程入门示例 : http://quicker.iteye.com/blog/571544
Mybatis,Ibatis,添加,修改,删除,获得结果集: http://javapub.iteye.com/blog/866913