MyBatis入门指南

cwf8 9年前

MyBatis起源于 iBatis,iBatis是Clinton Begin在2002年发起的开源项目,于2010年6月16日从Apache的网站退役,并被Google Code托管,改名为MyBatis。MyBatis是一个支持普通SQL查询、存储过程和高级映射的优秀的持久层框架,它消除了几乎所有的JDBC代 码、对参数的手工设置以及对结果集繁琐的处理,使用简单的XML或注解(annotation)用于配置和映射,将接口和POJO(Plain Old Java Object)映射成数据库中的记录。MyBatis最新的版本可以在github上获得,而它的文档则可以通过下面的链接得到。

下载地址:https://github.com/mybatis/mybatis-3/releases

中文文档:http://mybatis.github.io/mybatis-3/zh/index.html

相对于Hibernate这样复杂的ORM(对象关系映射)框 架而言,MyBatis只能算得上是一种半自动化的ORM实现,像Hibernate这样框架提供了对数据库结构提供了较为完整的封装,提供了从POJO 到数据库表的全套映射机制。程序员往往只需定义好了POJO 到数据库表的映射关系(通过XML或注解都可以完成),即可完成持久层操作;程序员甚至不需要熟练掌握的掌握SQL,因为Hibernate会自动生成对 应的SQL语句并通过JDBC代码加以执行。大多数情况下这样的机制无往不利,因此像Hibernate这样的框架在ORM领域大有一统天下的势头。但 是,封装得越好的东西,用户能定制的操作就越少,在一些特定的场景下,Hibernate这样的框架就未必能派上用场。例如:
1. 系统的部分或全部数据来自现有数据库,处于安全考虑,只对开发团队提供几条SQL语句(或存储过程)以获取所需数据,具体的表结构不予公开。
2. 开发规范中要求,所有牵涉到业务逻辑部分的数据库操作,必须在数据库层由存储过程实现。
3. 系统数据处理量巨大,性能要求极为苛刻,这往往意味着我们必须通过经过高度优化的SQL语句(或存储过程)才能达到系统性能设计指标。
以上列举的这几条在金融行业的项目中可以说屡见不鲜,这个时候你会发现Hibernate几乎无能为力,JDBC反而成为了不错的选择,但是JDBC中乏 味的字段读取操作是非常恶心的。在这样的场景下,半自动化的MyBatis刚好能满足需求。

使用MyBatis需要向你的项目中加入从上面的下载地址中下载到的JAR文件,当然,如果你使用了Maven,可以在pom.xml文件中加入对MyBatis的依赖。


每一个MyBatis应 用都以一个SqlSessionFactory对象的实例为核心,SqlSessionFactory对象可以通过 SqlSessionFactoryBuilder对象来获得,SqlSessionFactoryBuilder可以根据XML配置文件创建出 SqlSessionFactory对象。让我们先看一下配置文件config.xml的内容:

    <?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="User" type="com.lovo.entity.User" />                <typeAlias alias="Article" type="com.lovo.entity.Article" />            </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/mybatis" />                        <property name="username" value="root" />                        <property name="password" value="123456" />                    </dataSource>                </environment>            </environments>                    <mappers>                <mapper resource="com/lovo/entity/User.xml" />                <mapper resource="com/lovo/entity/Article.xml" />            </mappers>        </configuration>  

可以通过SessionFactory对象的openSession()方法创建SqlSession对象,SqlSession 对象完全包含以数据库为背景的所有执行SQL操作的方法,可以用SqlSession实例来直接执行已映射的SQL语句;当然,更简洁的方式是使用接口来封装对数据的操作。以下是实体类和映射文件。

用户类User.java:

    package com.lovo.entity;                public class User {            private String username;            private String password;            private String email;                    public String getUsername() {                return username;            }                    public void setUsername(String username) {                this.username = username;            }                    public String getPassword() {                return password;            }                    public void setPassword(String password) {                this.password = password;            }                    public String getEmail() {                return email;            }                    public void setEmail(String email) {                this.email = email;            }                    @Override            public String toString() {                return "User [username=" + username + ", password=" + password                        + ", email=" + email + "]";            }                }  

用户映射文件User.xml:

    <?xml version="1.0" encoding="UTF-8" ?>        <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">                <mapper namespace="com.lovo.dao.UserDao">            <select id="findByUsername" parameterType="String" resultType="User">                select * from tb_user where username=#{username}            </select>                        <select id="findAll" resultType="User">                select * from tb_user            </select>                        <insert id="save" parameterType="User" keyProperty="username">                insert into tb_user (username, password, email) values (#{username}, #{password}, #{email})            </insert>        </mapper>  


</div> </div>

帖子类:

    package com.lovo.entity;                import java.util.Date;                public class Article {            private int id;            private String content;            private User user;            private Date pubdate;                    public int getId() {                return id;            }                    public void setId(int id) {                this.id = id;            }                    public String getContent() {                return content;            }                    public void setContent(String content) {                this.content = content;            }                    public User getUser() {                return user;            }                    public void setUser(User user) {                this.user = user;            }                    public Date getPubdate() {                return pubdate;            }                    public void setPubdate(Date pubdate) {                this.pubdate = pubdate;            }                    @Override            public String toString() {                return "Article [id=" + id + ", content=" + content + ", user=" + user.toString()                        + ", pubdate=" + pubdate + "]";            }                            }  


</div> </div> 帖子映射文件Article.xml:
    <?xml version="1.0" encoding="UTF-8" ?>        <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">                <mapper namespace="com.lovo.dao.ArticleDao">            <resultMap type="Article" id="resultArticle">                <id property="id" column="id"/>                <result property="content" column="content"/>                <result property="pubdate" column="pubdate"/>                <association property="user" javaType="User">                    <id property="username" column="username" />                    <result property="email" column="email"/>                </association>            </resultMap>                    <select id="findAll" resultMap="resultArticle">                select t1.username, t1.email, t2.id, t2.content, t2.pubdate from tb_user as t1, tb_article as t2 where t1.username=t2.userid            </select>        </mapper>  


</div> </div> UserDao接口:

    package com.lovo.dao;                import java.util.List;                import com.lovo.entity.User;                public interface UserDao {                    public User findByUsername(String username);                        public List<User> findAll();                        public void save(User user);        }  


</div> </div>

ArticleDao接口:

    package com.lovo.dao;                import java.util.List;                import com.lovo.entity.Article;                public interface ArticleDao {                    public List<Article> findAll();        }  
</div> </div>

测试代码Test.java:

    package com.lovo.test;                import java.io.Reader;        import java.util.List;                import org.apache.ibatis.io.Resources;        import org.apache.ibatis.session.SqlSession;        import org.apache.ibatis.session.SqlSessionFactory;        import org.apache.ibatis.session.SqlSessionFactoryBuilder;                import com.lovo.dao.ArticleDao;        import com.lovo.entity.Article;                public class Test {                    public static void main(String[] args) throws Exception {                Reader reader = Resources.getResourceAsReader("config.xml");                SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);                SqlSession session = sessionFactory.openSession();                try {                    ArticleDao aDao = session.getMapper(ArticleDao.class);                    List<Article> list = aDao.findAll();                    for(Article a: list) {                        System.out.println(a);                    }                    System.out.println("End!");                } finally {                    session.close();                }                            }        }  

派生到我的代码片
</div> </div>
需要指出的是 SqlSessionFactoryBuilder类的对象一旦创建出SqlSessionFactory后就没有用了,可以被丢弃;而 SqlSessionFactory对象一旦被创建,应该在整个应用程序执行期间都是存在的,最好是做成被其他程序共享的单例。对于 SqlSession,每 个线程都应该有它自己的SqlSession实例。SqlSession的实例不能被共享,因为它是线程不安全的,它的最佳作用范围是请求或方法范围。绝 对不能将SqlSession实例的引用放在一个类的静态字段甚至是实例字段中,也绝不能SqlSession实例的引用放在任何类型的管理范围中,例如 Serlvet的HttpSession中。不管你使用什么样的Web框架,要考虑将SqlSession放在一个和 HTTP 请求对象相似的作用范围内。换句话说,基于收到的 HTTP 请求,你可以打开 了一个 SqlSession,然后返回响应,就可以关闭它了。关闭Session很重要,最好的选择是在finally代码块中关闭它。