以前用过一次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 {
    /**
     * serialVersionUID
     */
    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和字段之间的对应。
<?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
      </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接口,为了方便进行单元测试和类型安全,新版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<Test> 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;
    }
    /**
     * select测试
     * 
     * @param id
     * @return
     */
    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;
    }
    /**
     * select翻页测试
     * 
     * @param pg
     * @param pz
     * @return
     */
    @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;
    }
    /**
     * insert测试
     * 
     * @param t
     * @return
     */
    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;
    }
    /**
     * update测试
     * 
     * @param t
     * @return
     */
    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;
    }
    /**
     * delete测试
     * 
     * @param id
     * @return
     */
    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 {
    /**
     * @param args
     */
    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;
    }
    /**
     * select测试
     * 
     * @param id
     * @return
     */
    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;
    }
    /**
     * select翻页测试
     * 
     * @param pg
     * @param pz
     * @return
     */
    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;
    }
    /**
     * insert测试
     * 
     * @param t
     * @return
     */
    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;
    }
    /**
     * update测试
     * 
     * @param t
     * @return
     */
    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;
    }
    /**
     * delete测试
     * 
     * @param id
     * @return
     */
    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的代码生成工具。
    以上是个人观点,没有任何权威性,希望各位看过的朋友批评指正。