aoe1231

看得完吗

MyBatis入门

1、MyBatis的简介

1.1、原始jdbc操作(查询数据)

1.2、原始jdbc操作的分析

原始jdbc开发存在的问题如下:

  • 数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能;
  • sql语句在代码中硬编码,造成代码不易维护,实际应用sql变化的可能性较大,sql变动需要改变java代码;
  • 查询操作时,需要手动将结果集中的数据手动封装到实体中,插入操作时,需要手动将实体的数据设置到sql语句的占位符位置。

应对上述问题给出的解决方案:

  • 使用数据库连接池初始化连接资源;
  • 将sql语句抽取到xml配置文件中;
  • 使用反射、内省等底层技术,自动将实体与表进行属性与字段的自动映射。

1.3、什么是MyBatis

  1. mybatis是一个优秀的基于java 的持久层框架,它内部封装了jdbc,使开发者只需要关注sql语句本身,而不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。
  2. mybatis通过xml或注解的方式将要执行的各种statement配置起来,并通过java对象和statement中sql的动态参数进行映射生成最终执行的sql语句。
  3. 最后mybatis框架执行sql并将结果映射为java对象并返回。采用ORM思想解决了实体和数据库映射的问题,对jdbc进行了封装,屏蔽了jdbc api底层访问细节,使我们不用与jdbc api打交道,就可以完成对数据的持久化操作。

2、MyBatis的快速入门

2.1、MyBatis开发步骤

MyBatis官网地址:http://www.mybatis.org/mybatis-3/

MyBatis开发步骤:

  1. 添加Mybatis的坐标;
  2. 创建user数据表;
  3. 编写User实体类;
  4. 编写映射文件UserMapper.xml;
  5. 编写核心文件SqlMapConfig.xml;
  6. 编写测试类。
pom.xml:

        ...
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.32</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
        ...
package com.domain;

public class User {
    private int id;
    private String username;
    private String password;

    public int getId() {
        return id;
    }

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

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

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
UserMapper.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="userMapper">
    <select id="findAll" resultType="com.domain.User">
        select * from user
    </select>
</mapper>
sqlMapConfig.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>
    <!--配置数据源环境-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/db?characterEncoding=utf-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <!--加载映射文件-->
    <mappers>
        <mapper resource="com/mapper/UserMapper.xml"></mapper>
    </mappers>
</configuration>
package com.test;

import com.domain.User;
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 org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class MyBatisTest {
    @Test
    public void test1() throws IOException {
        //获得核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //获得session工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获得session会话对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //执行操作 参数:namespace+id
        List<User> userList = sqlSession.selectList("userMapper.findAll");
        //打印数据
        System.out.println(userList);
        //释放资源
        sqlSession.close();
    }
}

3、MyBatis的映射文件概述

4、MyBatis的增删改查

4.1、插入操作要注意的问题

  • 插入语句使用insert标签;
  • 在映射文件中使用parameterType属性指定要插入的数据类型;
  • Sql语句中使用#{实体属性名}方式引用实体中的属性值;
  • 插入操作使用的API是sqlSession.insert("命名空间.id",实体对象);
  • 插入操作涉及数据库数据变化,所以要使用sqlSession对象显式地提交事务,即sqlSession.commit()。

4.2、修改操作要注意的问题

  • 修改语句使用update标签;
  • 修改操作使用的API是sqlSession.update("命名空间.id",实体对象)。
  • 事务要手动进行提交。

4.3、删除操作要注意的问题

  • 删除语句使用delete标签;
  • Sql语句中使用#{任意字符串}方式引用传递的单个参数;
  • 删除操作使用的API是sqlSession.delete("命名空间.id",Object);
  • 事务要手动进行提交。
userMapper.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.clp.mapper.UserMapper">
    <!--插入操作-->
    <insert id="save" parameterType="user">
        insert into user values(#{id},#{username},#{password},#{birthday})
    </insert>

    <!--修改操作-->
    <update id="update" parameterType="user">
        update user set username=#{username},password=#{password} where id=#{id}
    </update>

    <!--删除操作-->
    <delete id="delete" parameterType="java.lang.Integer">
        delete from user where id=#{id}
    </delete>

    <!--根据id查询-->
    <select id="findById" parameterType="int" resultType="user">
        select * from user where id=#{id}
    </select>

    <!--查询操作-->
    <select id="findAll" resultType="user">
        select * from user
    </select>

</mapper>
package com.test;

import com.domain.User;
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 org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class MyBatisTest {
    @Test
    //查询操作
    public void test1() throws IOException {
        //获得核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //获得session工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获得session会话对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //执行操作 参数:namespace+id
        List<User> userList = sqlSession.selectList("userMapper.findAll");
        //打印数据
        System.out.println(userList);
        //释放资源
        sqlSession.close();
    }

    @Test
    //插入操作
    public void test2() throws IOException {
        //模拟user对象
        User user = new User();
        user.setId(1);
        user.setUsername("张三");
        user.setPassword("123456");

        //获得核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //获得session工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获得session会话对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //执行操作
        sqlSession.insert("userMapper.save",user);
        //mybatis执行更新操作,需要提交事务
        sqlSession.commit();
        //释放资源
        sqlSession.close();
    }

    @Test
    //修改操作
    public void test3() throws IOException {
        //模拟user对象
        User user = new User();
        user.setId(1);
        user.setUsername("张三");
        user.setPassword("123456");

        //获得核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //获得session工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获得session会话对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //执行操作
        sqlSession.update("userMapper.update",user);
        //提交事务
        sqlSession.commit();
        //释放资源
        sqlSession.close();
    }

    @Test
    //删除操作
    public void test4() throws IOException {
        //获得核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //获得session工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获得session会话对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //执行操作
        sqlSession.delete("userMapper.delete",7);
        //提交事务
        sqlSession.commit();
        //释放资源
        sqlSession.close();
    }
}

5、MyBatis核心配置文件概述

configuration 配置
    properties 属性
    settings 设置
    typeAliases 类型别名
    typeHandlers 类型处理器
    objectFactory 对象工厂
    plugins 插件
    environments 环境
        environment 环境变量
            transactionManager 事务管理器
            dataSource 数据源
    databaseIdProvider 数据库厂商标识
    mappers 映射器

5.1、MyBatis常用配置解析

5.1.1、environments标签

数据库环境的配置,支持多环境配置。

其中,事务管理器(transactionManager)类型有两种:

  • JDBC:这个配置就是直接使用了JDBC的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域。
  • MANAGED:这个配置几乎没做什么,它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如JEE应用服务器的上下文)。默认情况下它会关闭连接,然而一些容器并不希望这样,因此需要将closeConnection属性设置为false来组织它默认关闭的行为。

其中,数据源(dateSource)类型有三种:

  • UNPOOLED:设个数据源的实现只是每次请求时打开和关闭连接。
  • POOLED:这种数据源的实现利用“池”的概念将JDBC连接对象组织起来。
  • JNDI:这个数据源的实现是为了能在如EJB或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个JNDI上下文的引用。

5.1.2、mappers标签

sqlMapConfig.xml:

    ...
    <!--加载映射文件-->
    <mappers>
        <mapper resource="com/mapper/UserMapper.xml"></mapper>
    </mappers>
    ...

该标签的作用是加载映射的,加载方式有如下几种:

  • 使用相对于类路径的资源引用,例如:<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  • 使用完全限定资源定位符(URL),例如:<mapper url="file:///var/mappers/AuthorMapper.xml"/>
  • 使用映射器接口实现类的完全限定名,例如:<mapper class="org.mybatis.builder.AuthorMapper"/>
  • 将包内的映射器接口实现全部注册为映射器,例如:<package name="org.mybatis.builder" />

5.1.3、Properties标签

实际开发中,习惯将数据源的配置信息单独抽取成一个properties文件,该标签可以加载额外配置的properties文件。

5.1.4、typeAliases标签

类型别名是为Java类型设置一个短的名字,原来的类型名称配置如下:


    <select id="findAll" resultType="com.domain.User">
        select * from user
    </select>

配置typeAliases,为com.domain.User定义别名为user

mybatis框架已经为我们设置好了一些常用的类型的别名。

别名 数据类型
string String
long Long
int Integer
double Double
boolean Boolean
... ...

6、MyBatis的相应API

6.1、SqlSession工厂构建器SqlSessionFactoryBuilder

常用API:SqlSessionFactory build(InputStream inputStream)

通过加载mybatis的核心文件的输入流的形式构建一个SqlSessionFactory对象。

String resource = "org/mybatis/builder/mybatis-config.xml";
InputStream inputStream = Resource.getResourceAsStream(resource);
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(inputStream);

其中,Resource工具类,这个类在org.apache.ibatis.io包中。Resource类帮助你从类路径下、文件系统或一个web URL中加载资源文件。

6.2、SqlSession工厂对象SqlSessionFactory

SqlSessionFactory有多个方法创建SqlSession实例。常用的有如下两个:

方法 解释
openSession() 会默认开启一个事务,但事务不会自动提交,也就是意味着需要手动提交该事务,更新操作数据才会持久化到数据库中。
openSession(boolean autoCommit) 参数为是否自动提交,如果设置为true,那么不需要手动提交事务。

6.3、SqlSession会话对象

SqlSession实例在MyBatis中是非常强大的一个类。在这里你会看到所有执行语句、提交或回滚事务和获取映射器实例的方法。

执行语句的方法主要有:
    <T> T selectOne(String statement, Object parameter);
    <E> List<E> selectList(String statement, Object parameter);
    int insert(String statement, Object parameter);
    int update(String statement, Object parameter);
    int delete(String statement, Object parameter);

操作事务的方法主要有:
    void commit();
    void rollback();

7、MyBatis的Dao层实现

7.1、传统开发方式

7.1.1、编写UserDao接口

public interface UserDao {
    List<User> findAll() throws IOException;
}

8、MyBatis注解开发

8.1、MyBatis的常用注解

这几年来注解开发越来越流行,MyBatis也可以使用注解开发方式,这样我们就可以减少编写Mapper映射文件了。我们先围绕一些基本的CRUD来学习,再学习复杂映射多表操作。

-实现新增
@Insert

-实现更新
@Update

-实现删除
@Delete

-实现查询
@Select

-实现结果集封装
@Result

-可以与@Result一起使用,封装多个结果集
@Results

-实现一对一结果集封装
@One

-实现一对多结果集封装
@Many

8.2、MyBatis的增删改查

package com.clp.domain;

import lombok.Data;

import java.util.Date;

@Data
public class User {
    private int id;
    private String username;
    private String password;
    private Date birthday;
}
package com.clp.mapper;

import com.clp.domain.User;
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 java.util.List;

public interface UserMapper {
    /**
     * <!--加载映射关系(sqlMapConfig.xml)-->
     * <mappers>
     *     <!--指定接口所在的包-->
     *     <package name='com.clp.mapper'></package>
     * </mappers>
     *
     *
     * @param user
     */

    @Insert("insert into user values(#{id}, #{username}, #{password}, #{birthday})")
    public void save(User user);

    @Update("update user set username=#{username}, password=#{password} where id=#{id}")
    public void update(User user);

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

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

    @Select("select * from user")
    public List<User> findAll();
}

8.3、MyBatis的注解实现复杂映射开发

实现复杂关系映射之前我们可以在映射文件中通过配置<resultMap>来实现,使用注解开发后,我们可以使用@Result注解,@Result注解,@Many注解完成复杂关系的配置。

注解 说明
@Results 代替的是标签<resultMap>。该注解中可以使用单个@Result注解,也可以使用@Result集合。使用格式:@Results({@Result (), @Result ()})或@Results(@Result ())
@Result

代替了<id>标签和<result>标签。@Result中属性介绍:

column:数据库的列名;

property:需要装配的属性名;

one:需要使用的@One注解(@Result(one=@One)());

many:需要使用的@Many注解(@Result(many=@Many()))

@One

代替了<association>标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。

@One注解属性介绍:

select:指定用来多表查询的sqlmapper;

使用格式:@Result(column="",property="",one=@One(select=""))

@Many

代替了<collection>标签,是多表查询的关键,在注解中用来指定子查询返回对象集合。

使用格式:@Result(property="",column="",many=@Many(select=""))

8.4、一对一查询

package com.clp.domain;

import lombok.Data;

import java.util.Date;

/**
 * 订单
 */
@Data
public class Order {
    private int id;
    private Date ordertime;
    private double total;
    private User user; //当前订单属于哪个用户
}
package com.clp.mapper;

import com.clp.domain.Order;
import org.apache.ibatis.annotations.*;

import java.util.List;

@Mapper
public interface OrderMapper {
    /**
     * 方式 1
     * @return
     */
    @Select("select *,o.id oid from orders o, user u where o.uid = u.id")
    @Results({
            @Result(column = "oid", property = "id"), //将oid字段封装到Order中的id属性值中
            @Result(column = "ordertime", property = "ordertime"),
            @Result(column = "total", property = "total"),
            @Result(column = "uid", property = "user.id"),
            @Result(column = "username", property = "user.username"),
            @Result(column = "password", property = "user.password"),
            @Result(column = "birthday", property = "user.birthday")
    })
    public List<Order> findAll();

//    /**
//     * 方式 2
//     * @return
//     */
//    @Select("select * from orders")
//    @Results({
//            @Result(column = "oid", property = "id"), //将oid字段封装到Order中的id属性值中
//            @Result(column = "ordertime", property = "ordertime"),
//            @Result(column = "total", property = "total"),
//            @Result(
//                    property = "user", //要封装的属性名称
//                    column = "uid", //根据哪个字段去查询user表的数据
//                    javaType = User.class, //要封装的实体类型
//                    //select属性,代表查询哪个接口的方法获得数据
//                    one = @One(select = "com.clp.mapper.UserMapper.findById")
//            )
//    })
//    public List<Order> findAll();
}

8.5、一对多查询

8.5.1、一对多查询的模型

用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户。

一对多查询的需求:查询一个用户,与此同时查询出该用户具有的订单。

public interface UserMapper {
    /**
     * <!--加载映射关系(sqlMapConfig.xml)-->
     * <mappers>
     *     <!--指定接口所在的包-->
     *     <package name='com.clp.mapper'></package>
     * </mappers>
     *
     *
     * @param user
     */

    @Select("select * from user")
    @Results({
            @Result(id=true, column = "id", property = "id"), // id = true 代表该属性为主键
            @Result(column = "username", property = "username"),
            @Result(column = "password", property = "password"),
            @Result(
                    property = "orderList",
                    column = "id",
                    javaType = List.class,
                    many = @Many(select = "com.clp.mapper.OrderMapper.findByUid")
            )}
    )
    public List<User> findUserAndOrderAll();
}

8.6、多对多查询

8.6.1、多对多查询的模型

用户表和角色表的关系为:一个用户有多个角色,一个角色被多个用户使用。多对多查询的需求:查询用户同时查询出该用户的所有角色。

public interface RoleMapper {
    @Select("select * from user_role ur, role r where ur.roleId=r.id and ur.userId=#{uid}")
    public List<Role> findByUid(int uid);
}

public interface UserMapper {
    /**
     * <!--加载映射关系(sqlMapConfig.xml)-->
     * <mappers>
     *     <!--指定接口所在的包-->
     *     <package name='com.clp.mapper'></package>
     * </mappers>
     *
     *
     * @param user
     */
    
    @Select("select * from user")
    @Results({
            @Result(id = true, column = "id", property = "id"),
            @Result(column = "username", property = "username"),
            @Result(column = "password", property = "password"),
            @Result(
                    property = "roleList",
                    column = "id",
                    javaType = List.class,
                    many = @Many(select = "com.clp.mapper.RoleMapper.findByUid")
            )
    })
    public List<User> findUserAndRoleAll();
}

 

posted on 2022-09-18 15:48  啊噢1231  阅读(67)  评论(0编辑  收藏  举报

导航

回到顶部