iBatis初体验

1.什么是iBatis
iBatis属于ORM范畴,但它仅相当于半个ORM,因为使用iBatis仍然要写SQL,而不是SQL全部由ORM工具自动生成,iBatis更关注SQL所需参数,以及SQL返回的结果集到POJO的映射。

优势:
1)应用的持久层操作的是数据对象,而非jdbc的ResultSet,减轻了持久层的工作量,并使代码更加清晰、简洁。
2)对于性能要求高的,可以针对SQL做优化,以达到最佳的数据库执行性能,使用iBatis更加灵活、自由,程序员都是向往自由滴。

劣势:
1)仍然需要手动写SQL语句。
2)无法保证数据库兼容,即无法跨数据库。



2.iBatis之Helloworld
数据库表 person:

CREATE TABLE `person` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  `sex` varchar(2) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
)

通过iBatis 2.0实现对person表的增删该查功能,下面是代码和配置文件。
代码目录截图:




iBatis主配置文件:
sqlMapConfig.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN" "http://www.ibatis.com/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
    <properties resource="org/frank1234/ibatis/helloworld/sqlMapConfig.properties"></properties>
    <transactionManager type="JDBC">
        <dataSource type="SIMPLE">
            <property name="JDBC.Driver" value="${driver}"/>
            <property name="JDBC.ConnectionURL" value="${url}"/>
            <property name="JDBC.Username" value="${username}"/>
            <property name="JDBC.Password" value="${password}"/>
        </dataSource>
    </transactionManager>
    <sqlMap resource="org/frank1234/ibatis/helloworld/person.xml"/>

</sqlMapConfig>


注意其中的resource必须写相对于classpath的全路径。
transactionManager中的type和dataSource中的type暂时不解释。


这里数据库配置信息,引用了另外一个配置文件sqlMapConfig.properties
sqlMapConfig.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/demo
username=root
password=frank1234


跟数据库表对应的数据对象:
Person类
public class Person {
     private int id;
     private String name;
     private int age;
     private String sex;

     public Person(int id, String name, int age, String sex) {
         this.id = id;
         this.name = name;
         this.age = age;
         this.sex = sex;
     }
//这个是必须有,不是可以有。
     public Person() {
     }

     public int getId() {
         return id;
     }

     public void setId(int id) {
         this.id = id;
     }

     public String getName() {
         return name;
     }

     public void setName(String name) {
         this.name = name;
     }

     public int getAge() {
         return age;
     }

     public void setAge(int age) {
         this.age = age;
     }

     public String getSex() {
         return sex;
     }

     public void setSex(String sex) {
         this.sex = sex;
     }
     public String toString(){
        return "id="+id+",name="+name+",age="+age+",sex="+sex;
    }
}


sqlMap配置文件:
person.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "http://www.ibatis.com/dtd/sql-map-2.dtd">
<sqlMap namespace="person">
    <select id="getPerson" resultClass=" org.frank1234.ibatis.helloworld.Person">
        select id,name,sex,age from person where id=#value#
    </select>
    <insert id="savePerson" parameterClass="org.frank1234.ibatis.helloworld.Person">
        insert into person(name,sex,age) values(#name#,#sex#,#age#)
    </insert>
    <update id="updatePerson" parameterClass="org.frank1234.ibatis.helloworld.Person">
        update person set name=#name#,sex=#sex#,age=#age# where id=#id#
    </update>
    <delete id="deletePerson" parameterClass="org.frank1234.ibatis.helloworld.Person">
        delete from person where id=#id#
    </delete>
</sqlMap>


iBatis通过Person对象的getter和setter方法完成入参的赋值,以及返回值到Person对象的封装。

获取SqlMapClient的工具类:
IBatisUtil类,其中使用了单例模式的双重校验锁。注意volatile变量和synchronized内部的if(sqlMap == null)判断。另外resource也是要写全路径。SqlMapClient是iBatis操作的核心。
public class IBatisUtil {
    private static volatile SqlMapClient sqlMap;
    public static SqlMapClient getSqlMap(){
        if(sqlMap == null){
            synchronized (IBatisUtil.class){
                if(sqlMap == null){
                    try {
                        String resource = "org/frank1234/ibatis/helloworld/sqlMapConfig.xml";
                        Reader reader = Resources.getResourceAsReader(resource);
                        sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return sqlMap;
    }
}


测试类:
IBatisHelloworldMain类:
public class IBatisHelloworldMain {
    public static void main(String[] args) throws Exception{
//        save();
    get();
//        update();
//        delete();

    }
   public static void get() throws Exception{
        SqlMapClient client = IBatisUtil.getSqlMap();
        Person person = (Person)client.queryForObject("getPerson",new Integer(2));
        System.out.println(person);
    }
    public static void save() throws Exception{
        SqlMapClient client = IBatisUtil.getSqlMap();
        Person person = new Person();
        person.setName("frank1234");
        person.setAge(80);
        person.setSex("男");
        client.insert("savePerson",person);
    }
    public static void update() throws Exception{
        SqlMapClient client = IBatisUtil.getSqlMap();
//        client.startTransaction();
        Person person = new Person();
        person.setId(1);
        person.setName("frank12345");
        person.setSex("女");
        person.setAge(60);
        client.update("updatePerson", person);
    }
    public static void delete() throws Exception{
        SqlMapClient client = IBatisUtil.getSqlMap();
        Person person = new Person();
        person.setId(1);
        client.delete("deletePerson",person);
    }
}



3.几点补充
3.1 如何在控制台输出SQL
log4j的级别改为debug级别。
可在控制台见到如下输出:
2015-01-02 10:55:52,571: {conn-100000} Connection
2015-01-02 10:55:52,573: {conn-100000} Preparing Statement:          select id,name,sex,age from person where id=?    
2015-01-02 10:55:52,602: {pstm-100001} Executing Statement:          select id,name,sex,age from person where id=?    
2015-01-02 10:55:52,602: {pstm-100001} Parameters: [2]
2015-01-02 10:55:52,602: {pstm-100001} Types: [java.lang.Integer]
2015-01-02 10:55:52,604: {rset-100002} ResultSet
2015-01-02 10:55:52,616: {rset-100002} Header: [id, name, sex, age]
2015-01-02 10:55:52,616: {rset-100002} Result: [2, frank1234, 男, 80]

3.2 别名
参见helloworld示例中的sqlmap文件
每个parameterClass="org.frank1234.ibatis.helloworld.Person"都得写全路径,很烦。
这个可以通过别名来解决:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "http://www.ibatis.com/dtd/sql-map-2.dtd">
<sqlMap namespace="person">
    <typeAlias alias="person" type="org.frank1234.ibatis.helloworld.Person"/>
        <select id="getPerson" resultClass="person" >
        select id,name,sex,age from person where id=#value#
    </select>
  </sqlMap>


这下resultClass直接写成person就可以了。


3.3 命名空间
因为操作数据库通过sqlMap中定义的id来操作,这需要保证每个sqlMap中的id是唯一的,对于一个有很多人参与的大型项目,如果没有很好的规范和功能划分的话,很容易id重复,使用namespace可以解决这个问题。

首先:主配置文件中打开namespace,默认是关闭的
<sqlMapConfig>
    <properties resource="org/frank1234/ibatis/helloworld/sqlMapConfig.properties"></properties>
    <settings useStatementNamespaces="true"/>

</sqlMapConfig>


然后在sqlMap配置文件中配置namespace
<sqlMap namespace=" person">
    <typeAlias alias="person" type="org.frank1234.ibatis.helloworld.Person"/>
       <insert id=" savePerson" parameterClass="org.frank1234.ibatis.helloworld.Person">
    insert into person(name,sex,age) values(#name#,#sex#,#age#)
</insert>
    </select>
  </sqlMap>


最后SqlMapClient操作的时候,比如对于之前的保存,需要写成:
client.insert("person.savePerson",person);

3.4 select的另一种方式
helloworld中的get()通过转型获取的Person对象,还有另外一种写法:
public static void get() throws Exception{
    SqlMapClient client = IBatisUtil.getSqlMap();
    Person person = new Person();
    client.queryForObject("getPerson",new Integer(2),person);
    System.out.println(person);
}



3.5 数据库字段和属性字段的对应
如果数据库字段的名字和对象属性的名字不一样,可通过as或者<ResultMap>元素来实现。
使用as更简洁。
例如:
<select id="getPerson" resultClass="person" >
    select id,xingming as name,xingbie as sex from person where id=#value#
</select>


这样就实现了数据库字段名为xingming和xingbie,而对象中为name和sex的映射。

3.6 数据库连接的另外几种获取方式
helloworld中datasource的获取方式为SIMPLE。
另外还有DBCP和JNDI两种获取方式。
DBCP只是type不同,子元素同SIMPLE一样:
<dataSource type="DBCP">
    <property name="JDBC.Driver" value="${driver}"/>
    <property name="JDBC.ConnectionURL" value="${url}"/>
    <property name="JDBC.Username" value="${username}"/>
    <property name="JDBC.Password" value="${password}"/>
</dataSource>


JNDI方式,这样可以集成第三方的数据库连接池,比如使用tomcat+c3p0连接池:
<dataSource type="JNDI">
    <property name="DataSource" value="java:comp/env/xxxDataSource"/>
</dataSource>


3.7 获取Connection对象
代码示例:
SqlMapClient client = IBatisUtil.getSqlMap();
SqlMapSession session = client.openSession();
Connection conn = session.getCurrentConnection();



猜你喜欢

转载自frank1234.iteye.com/blog/2171822