Mybatis详解

Mybatis详解

关于Mybatis的具体介绍请参考http://www.mybatis.org/mybatis-3/zh/

使用Mybatis时,直接导入相应的jar包就行,这里使用的是mybatis-3.4.1.jar

下面的例子,已一个users表为例,先创建表,再插入两条数据

CREATE TABLE users(id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20), age INT);
INSERT INTO users(NAME, age) VALUES('Tom', 12);
INSERT INTO users(NAME, age) VALUES('Jack', 11);

创建Mybatis程序的大致步骤是:

1.添加Mybatis 的配置文件Configuration.xml,主要配置了数据源等


    

    <configuration>


        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC">
                    <property name="" value="" />
                transactionManager>
                <dataSource type="UNPOOLED">
                    <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="" />
                dataSource>
            environment>
        environments>

    configuration>

一些说明:

a.transactionManager-事务管理器,在 MyBatis 中有两种类型的事务管理器(也就是 type=”[JDBC|MANAGED]”):

  • JDBC – 这个配置就是直接使用了 JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域。
  • MANAGED – 这个配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)

b.dataSource-数据源,dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源

2.创建实体类User和定义操作users 表的sql 映射文件userMapper.xml

首先创建实体类User

public class User {
    private int id;
    private String name;
    private int age;
    public int getId() {
        return id;
    }
    //get set方法
    ......
}   

然后创建user表的sql映射文件userMapper.xml
在这里定义了一个select语句,根据id查询到一个user对象

    
    

    <mapper namespace="mybatis.test1.userMapper">

        
        <select id="getUser" parameterType="int" resultType="mybatis.test1.User">
            select * from users where id=#{id}
        select>

    mapper>

注意的点:

  • #{id}-表示从传递过来的参数中取出id
  • namespace-相当于是唯一标识符,一般是包名+文件名
  • parameterType-表示参数的类型,这里是int
  • resultType表示的是返回值类型,这里是User类的全类名

3.在Configuration.xml文件中注册userMapper.xml 文件

注意:这里是路径的结构,不是包的结构

    <mappers>
        <mapper resource="mybatis/test1/userMapper.xml" />
    mappers>

4.执行定义的select 语句

        String resource = "Configuration.xml";
        //加载mybatis 的配置文件(它也加载关联的映射文件)
        Reader reader = Resources.getResourceAsReader(resource);
        //构建sqlSession 的工厂
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
        //创建能执行映射文件中sql 的sqlSession
        SqlSession session = sessionFactory.openSession();
        //映射sql 的标识字符串
        String statement = "mybatis.test1.userMapper"+".getUser";
        //执行查询返回一个唯一user 对象的sql
        User user = session.selectOne(statement, 1);
        System.out.println(user);

这里的statementuserMapper.xmlmappernamespace属性,加上selectid属性

String statement = "mybatis.test1.userMapper"+".getUser";

最后控制台输出的数据结果为:

User [id=1, name=Tom, age=12]

5.输出调用sql语句
为方便调试,可在控制条输出调用sql语句,具体实现参考MyBatis控制台输出SQL语句,注意settings标签的顺序

增删改查操作

有两种方式实现增删改查操作:

  • XML实现
  • 注解实现

XML实现

添加数据

添加数据要使用insert标签,如下:


    insert into users(name, age) values(#{name}, #{age})

  • parameterType表示参数的类型使用的是实体类User对象的全类名。
  • values(#{name}, #{age}#{}括号中对应的是实体类User类的属性

编写测试类,测试下:

    @Test
    public void testAdd() {
        int insert = session.insert("mybatis.test2.userMapper.addUser", new User(-1, "xiaozhao", 23));
        System.out.println(insert);
    }

返回值insert表示受影响的行数,此时提示是1,表示是成功的,但是此时去查看数据库,会发现并没有插入的数据。是因为session = sessionFactory.openSession();是需要手动提交事务的,所以需要使用如下的方式:

    int insert = session.insert("mybatis.test2.userMapper.addUser", new User(-1, "xiaozhao", 23));
    session.commit();

设置自动提交

session = sessionFactory.openSession(true);

删除数据

删除数据使用delete标签


    delete from users where id=#{id}

测试如下:

    int delete = session.delete("mybatis.test2.userMapper.deleteUser", 6);
    session.commit();

修改数据

修改数据使用update标签


    update users set name=#{name}, age=#{age} where id=#{id}

测试如下:

    int insert = session.update("mybatis.test2.userMapper.updateUser", new User(4, "xiaowang", 30));
    session.commit();

查询数据

查询单个对象

在xml中的配置如下:



使用selectOne方法获取查询的对象:

    User user = session.selectOne("mybatis.test2.userMapper.getUser", 1);
    session.commit();
    System.out.println(user);

查询所有对象

查询所有对象,表示返回值有多个对象,resultType表示list里面放的对象类型
在xml中配置如下:

 

使用selectList获取所有对象,测试如下:

        List users = session.selectList("mybatis.test2.userMapper.getAllUsers");
        session.commit();
        System.out.println(users);

注解实现

基于注解实现,需先定义sql映射的接口,把所有的sql语句写到接口中

    package mybatis.test3;

    import java.util.List;

    import org.apache.ibatis.annotations.Delete;
    import org.apache.ibatis.annotations.Insert;
    import org.apache.ibatis.annotations.Select;
    import org.apache.ibatis.annotations.Update;

    import mybatis.test2.User;

    public interface UserMapper {

        @Insert("insert into users(name, age) values(#{name}, #{age})")
        public int add(User user);

        @Delete("delete from users where id=#{id}")
        public int deleteById(int id);

        @Update("update users set name=#{name}, age=#{age} where id=#{id}")
        public int update(User user);

        @Select("select * from users where id=#{id}")
        public User getById(int id);

        @Select("select * from users")
        public List getAll();


    }

将接口文件添加到Configuration.xmlmappers中,注意与映射文件的区别


    

测试添加如下:

        UserMapper mapper = session.getMapper(UserMapper.class);
        int add = mapper.add(new User(-1, "xiaoqian", 23));
        session.commit();
        System.out.println(add);

优化

数据库连接单独放在一个文件

创建db.properties文件

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis
username=root
password=

Configuration.xml中导入文件


dataSource标签中引用这些值:

        
            
            
            
            
        

为实体类定义别名,简化sql 映射xml 文件中的引用

1.定义别名
在上述的的映射文件中,总在重复的写全类名,如mybatis.test1.User,而mybatis.test1.User在很多地方都要重用

<select id="getUser" parameterType="int" resultType="mybatis.test1.User">
    select * from users where id=#{id}
select>

所以可以在Configuration.xml中配置全类名的别名



    

使用别名

 

2.扫描包方式

参考Mybatis之typeAlias配置的3种方法

通过package, 可以直接指定package的名字, mybatis会自动扫描你指定包下面的javabean,
并且默认设置一个别名,默认的名字为: javabean 的首字母小写的非限定类名来作为它的别名。

<typeAliases>
     <package name="cn.lxc.vo" />
typeAliases>

3.注解方式

package cn.lxc.vo;

import org.apache.ibatis.type.Alias;

@Alias("User")
public class User {
    private int id;
    private String name;
    private int age;

    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;
    }
}

可以在src 下加入log4j 的配置文件,打印日志信息

添加相应的jar包, log4j.properties配置信息如下:

log4j.properties,
log4j.rootLogger=DEBUG, Console
#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

也可以使用xml方式来配置log4j,如下的log4j.xml



<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
    <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern"
                value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n" />
        layout>
    appender>
    <logger name="java.sql">
        <level value="debug" />
    logger>
    <logger name="org.apache.ibatis">
        <level value="debug" />
    logger>
    <root>
        <level value="debug" />
        <appender-ref ref="STDOUT" />
    root>
log4j:configuration>

解决字段名与实体类属性名不相同的冲突

如下的例子中,表中的列名为order_no,而实体类中的属性名为orderNo,如何把它们对应起来呢?

创建如下的orders表:

CREATE TABLE orders(
order_id INT PRIMARY KEY AUTO_INCREMENT,
order_no VARCHAR(20),
order_price FLOAT
);
INSERT INTO orders(order_no, order_price) VALUES('aaaa', 23);
INSERT INTO orders(order_no, order_price) VALUES('bbbb', 33);
INSERT INTO orders(order_no, order_price) VALUES('cccc', 22);

创建orders表对应的实体类,Order

package mybatis.bean;

public class Order {

    private int id;
    private String orderNo;
    private float price;

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getOrderNo() {
        return orderNo;
    }
    public void setOrderNo(String orderNo) {
        this.orderNo = orderNo;
    }
    public float getPrice() {
        return price;
    }
    public void setPrice(float price) {
        this.price = price;
    }

    public Order() {

    }

    public Order(int id, String orderNo, float price) {
        super();
        this.id = id;
        this.orderNo = orderNo;
        this.price = price;
    }

    @Override
    public String toString() {
        return "Order [id=" + id + ", orderNo=" + orderNo + ", price=" + price + "]";
    }

}

可以发现,字段名和属性名并不一致。

创建orderMapper.xml映射文件:






    
    


使用如下方式来获取order对象:

    Order order = session.selectOne("mybatis.test4.orderMapper.getOrder", 1);
    System.out.println(order);

会发现输出结果为null

如何显示order的查询呢?
1.通过在sql 语句中定义别名

如下给order_id起别名为id等等,是表的字段名与实体类属性名对应


这样之后,就可以正常获取值了

Order [id=1, orderNo=aaaa, price=23.0]

2.使用

使用来把表的字段名与实体类属性名对应

注意此时 select * from orders where order_id=#{id}

接口编程方式实现

上面使用的方式是用户比较熟悉的方式。现在有个更好的方式是,使用接口来描述statement的参数和返回值,这样执行起来可以更简洁和安全

如下的例子,先创建一个tbl_employee表,插入一条数据

create table tbl_employee(
    id int(11) primary key auto_increment,
    last_name varchar(255),
    gender char(1),
    email varchar(255)
);
insert into tbl_employee (last_name, gender, email) values('wz', 0, '[email protected]')

创建对应的实体类Employee

public class Employee {

    private Integer id;
    private String lastName;
    private String email;
    private String gender;

    //get set方法
    ......
}

如下先创建一个接口类EmployeeMapper

package com.wz.mybatis.dao;

import com.wz.mybatis.bean.Employee;

public interface EmployeeMapper {

    //更加id获取Employee
    public Employee getEmpById(Integer id);

}

接口要与映射文件EmpolyeeMapper.xml动态绑定,而对于xml映射文件EmpolyeeMapper.xml要注意:

  • namespace要指定为接口的全类名
  • select标签的id要与接口的方法名对应

EmpolyeeMapper.xml内容如下:



<mapper namespace="com.wz.mybatis.dao.EmployeeMapper">

    <select id="getEmpById" resultType="com.wz.mybatis.bean.Employee">
        select id, last_name lastName, gender, email from tbl_employee where id = #{id}
    select>

mapper>

其调用方式如下:

    public SqlSessionFactory getSqlSessionFactory() throws IOException{
        String resource = "mybatis-config.xml";
        // 加载mybatis 的配置文件(它也加载关联的映射文件)
        Reader reader = Resources.getResourceAsReader(resource);
        // 构建sqlSession 的工厂
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
        return sessionFactory;
    }

    public void test01() throws IOException {

        // 构建sqlSession 的工厂
        SqlSessionFactory sessionFactory = getSqlSessionFactory();
        // 创建能执行映射文件中sql 的sqlSession
        SqlSession session = sessionFactory.openSession();

        try {
            //获取接口的实现类对象
            EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
            Employee employee = mapper.getEmpById(1);

            System.out.println(mapper.getClass());
            System.out.println(employee);

        } finally {
            session.close();
        }

    }

其中System.out.println(mapper.getClass());的控制台输出的结果为class com.sun.proxy.$Proxy4,表示的是Mybatis会为接口创建一个代理对象,代理对象去执行增删改查方法

你可能感兴趣的:(Mybatis)