mybatis 3.0.2 试用小记

mybatis 3.0.2 试用小记

    以前用过一次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的代码生成工具。

    以上是个人观点,没有任何权威性,希望各位看过的朋友批评指正。

你可能感兴趣的:(mybatis 3.0.2 试用小记)