Mybatis


1.Mybatis简介

MyBatis本是apache的一个开源项目iBatis

SSM = Spring+SpringMVC+MyBatis
SSH= Spring+Struts+Hibernate

MyBatis 是一种优秀的持久层框架,它是一个基于 Java 的开源框架,用于简化数据库访问的开发。MyBatis 提供了灵活的映射方式,将对象与 SQL 语句进行映射,并提供了丰富的功能来处理数据库操作。

以下是 MyBatis 的特点和主要功能:

  • 灵活的映射:MyBatis 使用 XML 或注解来定义对象与 SQL 语句之间的映射关系,可以方便地进行 CRUD 操作。

  • SQL 控制:MyBatis 允许开发者编写原生 SQL,可以更灵活地控制 SQL 语句的编写和优化。

  • 参数绑定:MyBatis 支持将 Java 对象作为参数传递给 SQL 语句,通过占位符来进行参数绑定,可以有效避免 SQL 注入攻击。

  • 自动映射:MyBatis 可以根据对象与表的命名规则自动进行属性到字段的映射,大大减少了手动编写映射的工作。

  • 缓存支持:MyBatis 提供了一级缓存和二级缓存机制,可以加快数据访问效率。

  • 多数据库支持:MyBatis 支持多种数据库,包括 MySQL、Oracle、SQL Server 等。

  • 事务管理:MyBatis 可以通过配置开启事务管理,保证数据操作的一致性和完整性。

总的来说,MyBatis 提供了强大且灵活的数据库访问功能,能够帮助开发者更高效地进行数据库操作。它与 Spring 等框架集成使用,广泛应用于 Java 后端开发中。

2.JDBC开发存在的问题

sql语句写到了 daoimpl dao中 ,不利于系统的维护 sql写到了java代码中【硬编码】
解决方案: 将sql语句放到一个单独的文件中 【xml】

PreparedStatement 该对象需要处理问号 存在sql和java的硬编码问题
解决方案: 将sql和参数设置在 xml中

resultSet 进行遍历 使用列名或者序号获取数据 ,不利于系统的维护
解决方案: 将查询到的结果直接映射为 java对象

因为mybatis底层就是jdbc,使用mybatis的框架就可以解决上述问题。

3.Mybatis框架

https://mybatis.net.cn/

4.Mybatis的底层逻辑

在这里插入图片描述

1.SqlMapConfig.xml

SqlMapConfig.xml 是 MyBatis 的核心配置文件,用于配置 MyBatis 的全局属性和资源引用。

在 SqlMapConfig.xml 文件中,可以进行以下配置:

  1. 数据源配置:通过 元素配置数据库连接池的相关信息,包括数据库驱动、连接 URL、用户名、密码等。

  2. 事务管理器配置:通过 元素配置事务管理器,可以选择使用 MyBatis 默认的 JDBC 事务管理器或使用第三方的事务管理器。

  3. 类型别名配置:通过 元素配置类型别名,可以为 Java 类或接口设置别名,简化 SQL 映射文件中类型的引用。

  4. Mapper 文件配置:通过 元素配置 Mapper 文件的引入方式,可以使用 元素引入单个 Mapper 文件,也可以使用 元素批量引入一个包下的所有 Mapper 文件。

  5. 全局属性配置:通过 元素配置全局属性,可以在 MyBatis 的配置文件中定义一些全局通用的属性,供后续的配置项中引用。

除了上述常见的配置项外,SqlMapConfig.xml 还可以配置其他一些高级选项,例如插件、缓存配置、日志实现等。

以下是一个简单的 SqlMapConfig.xml 配置示例:

<configuration>
  <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/mydatabase"/>
        <property name="username" value="root"/>
        <property name="password" value="password"/>
      </dataSource>
    </environment>
  </environments>
  
  <mappers>
    <mapper resource="com/example/mapper/ExampleMapper.xml"/>
    <package name="com.example.mapper"/>
  </mappers>
</configuration>

以上示例配置了数据库连接池、事务管理器,引入了一个 Mapper 文件和一个包下的所有 Mapper 文件。

SqlMapConfig.xml 是 MyBatis 的主要配置文件之一,它提供了全局性的配置信息,为 MyBatis 的使用和功能扩展提供了基础。

2.会话工厂

会话工厂(SqlSessionFactory)是 MyBatis 的核心接口之一,用于创建 SqlSession 对象。在使用 MyBatis 进行数据库操作时,通常需要先创建会话工厂,然后通过会话工厂创建 SqlSession 对象,最终使用 SqlSession 对象进行数据库操作。

会话工厂的创建是一个比较耗时的操作,因此一般情况下一个应用只需要创建一个会话工厂即可,多个 SqlSession 实例可以共享同一个会话工厂。

MyBatis 提供了多种方式来创建会话工厂,其中常用的有以下两种:

1. XML 配置文件方式

使用 XML 配置文件方式创建会话工厂是 MyBatis 的传统方式,需要在配置文件中指定数据库连接信息、映射文件等。具体可以参考 MyBatis 的 SqlMapConfig.xml 配置文件。

示例代码:

InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sessionFactory.openSession();

以上代码使用 org.apache.ibatis.io.Resources 类的 getResourceAsStream() 方法加载 MyBatis 的 XML 配置文件,然后通过 SqlSessionFactoryBuilder 类的 build() 方法创建会话工厂对象,最终使用 SqlSessionFactory 的 openSession() 方法获取 SqlSession 对象进行数据库操作。

2.Java 代码方式

MyBatis 也支持使用 Java 代码方式创建会话工厂,相对于 XML 配置文件更加灵活。可以通过编写 Java 类来创建会话工厂,直接指定数据库连接信息、映射文件等。

示例代码:

DataSource dataSource = getDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(UserMapper.class);
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(configuration);

以上代码使用 javax.sql.DataSource 接口的实现类 getDataSource() 方法获取数据源对象,然后创建事务工厂、环境、配置对象,最终添加映射器并构建会话工厂对象。

总之,会话工厂是 MyBatis 中非常重要的核心组件,其创建方式决定了 MyBatis 的基本使用方式,需要根据项目的实际情况选择合适的创建方式。

5.Mybatis的主要开发模式

1.dao开发模式

MyBatis的DAO(Data Access Object)开发模式可以使用XML或注解两种方式来实现,下面我们将分别介绍这两种方式的基本用法。

  1. XML方式

在XML方式中,你需要编写一个Mapper XML文件,其中定义了一系列SQL语句,然后创建一个Mapper接口,与Mapper XML文件中定义的SQL语句相对应。以下是一个简单示例:

Mapper XML文件:

<!-- UserMapper.xml -->
<mapper namespace="com.example.dao.UserMapper">
    <select id="getUserById" resultType="com.example.entity.User">
        SELECT * FROM user WHERE id = #{id}
    </select>
</mapper>

Mapper接口:

// UserMapper.java
public interface UserMapper {
    User getUserById(Integer id);
}

在上面的示例中,我们创建了一个名为UserMapper的Mapper接口,并定义了一个getUserById方法,该方法使用了id参数来执行数据库查询操作,并返回User对象作为查询结果。在Mapper XML文件中,我们定义了一条SELECT语句来查询符合条件的用户信息,resultType属性指定了查询结果的Java类型。

  1. 注解方式

除了XML方式,MyBatis还支持注解方式来定义SQL语句和Mapper接口方法。以下是一个简单示例:

// UserMapper.java
@Mapper
public interface UserMapper {
    @Select("SELECT * FROM user WHERE id = #{id}")
    User getUserById(Integer id);
}

在上述示例中,我们在getUserById方法上使用了@Select注解来指定SQL语句。在@Select注解中,我们使用了${}占位符来表示查询条件。同时,我们还在UserMapper接口上使用了@Mapper注解,来告诉MyBatis该接口是一个Mapper接口。

无论是XML方式还是注解方式,都需要通过SqlSessionFactory创建SqlSession,然后通过SqlSession的getMapper方法来获取Mapper接口的实现,最终使用Mapper接口调用方法来执行对应的SQL语句。以下是一个示例代码:

// 创建SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);


// 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();

// 获取Mapper接口实现
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

// 调用Mapper方法执行SQL语句
User user = userMapper.getUserById(1);

// 关闭SqlSession
sqlSession.close();

在示例代码中,我们首先通过mybatis-config.xml配置文件来创建一个SqlSessionFactory对象,然后通过SqlSessionFactory创建SqlSession对象。接着,我们通过SqlSession的getMapper方法来获取UserMapper接口的实现,最后调用Mapper方法来执行相应的SQL查询语句。执行完毕后,我们需要关闭SqlSession。

2.mapper代理模式的开发

Mapper代理模式是MyBatis中一种简化Mapper接口实现的方式。通过Mapper代理模式,我们无需手动编写Mapper接口的实现类,而是由MyBatis框架动态生成Mapper接口的实现。

具体实现过程如下:

  1. 创建Mapper接口:首先,我们需要创建一个普通的Mapper接口,其中定义了各种数据库操作方法。
public interface UserMapper {
    User getUserById(Integer id);
    void insertUser(User user);
    void updateUser(User user);
    void deleteUser(Integer id);
}
  1. 编写Mapper XML文件:接下来,我们编写与Mapper接口对应的Mapper XML文件,其中定义了与接口方法对应的SQL语句。
<!-- UserMapper.xml -->
<mapper namespace="com.example.dao.UserMapper">
    <select id="getUserById" resultType="com.example.entity.User">
        SELECT * FROM user WHERE id = #{id}
    </select>
    <insert id="insertUser" parameterType="com.example.entity.User">
        INSERT INTO user (id, name, age) VALUES (#{id}, #{name}, #{age})
    </insert>
    <!-- 其他SQL语句省略 -->
</mapper>
  1. 配置映射关系:在MyBatis的配置文件中,配置Mapper接口和Mapper XML文件的映射关系。
<!-- mybatis-config.xml -->
<configuration>
    <mappers>
        <mapper resource="com/example/dao/UserMapper.xml"/>
        <!-- 其他Mapper XML文件省略 -->
    </mappers>
</configuration>

使用Mapper代理模式:在代码中,我们可以通过SqlSession的getMapper方法来获取Mapper接口的代理对象,并使用代理对象执行数据库操作。

SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

User user = userMapper.getUserById(1);
user.setName("Alice");
userMapper.updateUser(user);

sqlSession.commit();
sqlSession.close();

在上述代码中,我们首先通过SqlSessionFactory创建SqlSession对象,然后通过getMapper方法获取UserMapper接口的代理对象。通过代理对象,我们可以直接调用接口中定义的方法,例如getUserById()updateUser()等。MyBatis框架会根据接口方法的名称和参数类型,在底层动态生成SQL语句并执行,完成与数据库的交互操作。

需要注意的是,Mapper代理模式要求Mapper接口和Mapper XML文件的名称、位置和命名空间(namespace)保持一致,这样MyBatis才能正确地将XML中的SQL语句与接口方法关联起来。

  1. 在mapper.xml中namespace等于 mapper接口地址

  2. 在mapper.xml中statementID要和 mapper接口中的方法名保持一致
    //<select id=“findAll”
    public List findAll();

  3. 在mapper.xml中的resultType 要和 mapper.java中输出参数类型保持一致[返回值]
    resultType=“com.liushao.entity.User” public List findAll();

  4. 在mapper.xml中的parameterType 要和 mapper.java中输入参数类型保持一致[形参]
    public List findAll(); 目前木有

多表查询思路

一般多表查询的情况下要先确定主表
假设有一个用户表和一个订单表
然后写出sql语句

  <select id="findouodi" resultMap="douodi">
        SELECT
            user.*,
            orders.id or_id,
            orders.user_id,
            orders.number,
            orders.createtime,
            orders.note,
            orderdetail.id ord_id,
            orderdetail.orders_id,
            orderdetail.items_id,
            orderdetail.items_num,
            items.id it_id,
            items.name,
            items.price,
            items.detail
        FROM
            USER,
            orders,
            orderdetail,
            items
        WHERE user.`id`=orders.user_id
          AND orders.`id`=orderdetail.`orders_id`
          AND orderdetail.`items_id`=items.`id`


    </select>
    <resultMap id="douodi" type="entity.User">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="birthday" property="birthday"></result>
        <result column="sex" property="sex"></result>
        <result column="address" property="address"></result>
        <collection property="ordersList" ofType="entity.Orders">
            <id column="or_id" property="id"></id>
            <result column="user_id" property="userId"></result>
            <result column="number" property="number"></result>
            <result column="createtime" property="createtime"></result>
            <result column="note" property="note"></result>
            <collection property="orderdetails" ofType="entity.Orderdetail">
                <id column="ord_id" property="id" />
                <result column="items_id" property="itemsId"/>
                <result column="items_num" property="itemsNum"/>
                <result column="orders_id" property="ordersId"/>
                <association property="items" javaType="entity.Items" >
                    <id column="it_id" property="id"></id>
                    <result column="name" property="name"></result>
                    <result column="price" property="price"></result>
                    <result column="detail" property="detail"></result>
                    <result column="createtime" property="createtime"></result>
                </association>
            </collection>
        </collection>
    </resultMap>

测试

   @Test
    public void findUserListCount() {
        SqlSession sqlSession = factory.openSession();
        //获取代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

        List<User> findouod = userMapper.findouodi();
        System.out.println(findouod);

    }

看下这个多表查询,这是一个多对多 查询四个表。
注意 每个表都有id 但是这个<id>标签这里的column一定要起别名 如果不起别名会与其他表的id冲突,就会导致出现意想不到的结果

而且这里实体类我是以User用户为主表来进行查询,那么User实体类中就要多加上Orders ,因为Orders表在数据库中又与Ordersdetail有联系,那么Orders中要加上Ordersdetail属性
依此类推得出最终的四个实体类
User类

package entity;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


public class User implements Serializable {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;

    private List<Orders> ordersList =new ArrayList<>();

    public List<Orders> getOrdersList() {
        return ordersList;
    }

    public void setOrdersList(List<Orders> ordersList) {
        this.ordersList = ordersList;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", birthday=" + birthday +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                ", ordersList=" + ordersList +
                '}';
    }

    public User() {
    }

    public User(String username) {

        this.username = username;

    }

    public User(Integer id, String username, Date birthday, String sex, String address) {
        this.id = id;
        this.username = username;
        this.birthday = birthday;
        this.sex = sex;
        this.address = address;
    }

    public Integer getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

Orders实体类

package entity;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


public class Orders implements Serializable {
    public Integer id;
    public Integer userId;
    public String number;
    public Date createtime;
    public String note;

    @Override
    public String toString() {
        return "Orders{" +
                "id=" + id +
                ", userId=" + userId +
                ", number='" + number + '\'' +
                ", createtime=" + createtime +
                ", note='" + note + '\'' +
                ", orderdetails=" + orderdetails +
                '}';
    }

    //添加用户信息过来 用于使用 resultMap
 

    //订单明细的集合
    private List<Orderdetail> orderdetails= new ArrayList<>();

    public List<Orderdetail> getOrderdetails() {
        return orderdetails;
    }
    public void setOrderdetails(List<Orderdetail> orderdetails) {
        this.orderdetails = orderdetails;
    }



    public Orders(Integer id, Integer userId, String number, Date createtime, String note) {
        this.id = id;
        this.userId = userId;
        this.number = number;
        this.createtime = createtime;
        this.note = note;
    }

    public Orders() {}

    public Integer getId() {
        return id;
    }

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

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    public Date getCreatetime() {
        return createtime;
    }

    public void setCreatetime(Date createtime) {
        this.createtime = createtime;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }

}

Orderdetail实体类

package entity;
import java.io.Serializable;
import java.util.List;
public class Orderdetail  implements Serializable {
    private Integer id;
    private Integer ordersId;

    @Override
    public String toString() {
        return "Orderdetail{" +
                "id=" + id +
                ", ordersId=" + ordersId +
                ", itemsId=" + itemsId +
                ", itemsNum=" + itemsNum +
                ", items=" + items +
                '}';
    }

    private Integer itemsId;
    private Integer itemsNum;

    private Items items;


    public Orderdetail(Integer id, Integer ordersId, Integer itemsId, Integer itemsNum) {
        this.id = id;
        this.ordersId = ordersId;
        this.itemsId = itemsId;
        this.itemsNum = itemsNum;

    }

    public Integer getId() {
        return id;
    }

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

    public Integer getOrdersId() {
        return ordersId;
    }

    public void setOrdersId(Integer ordersId) {
        this.ordersId = ordersId;
    }

    public Integer getItemsId() {
        return itemsId;
    }

    public void setItemsId(Integer itemsId) {
        this.itemsId = itemsId;
    }

    public Integer getItemsNum() {
        return itemsNum;
    }

    public void setItemsNum(Integer itemsNum) {
        this.itemsNum = itemsNum;
    }



    public Orderdetail() {
    }
}

Items实体类

package entity;

import java.sql.Timestamp;
import java.util.Date;

public class Items {
    private Integer id;
    private String name;
    private Float price;

    private String detail;
    private String pic;
    private Timestamp createtime;

    public Items() {
    }

    @Override
    public String toString() {
        return "Items{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", price=" + price +
                ", detail='" + detail + '\'' +
                ", pic='" + pic + '\'' +
                ", createtime=" + createtime +
                '}';
    }

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public Float getPrice() {
        return price;
    }

    public void setPrice(Float price) {
        this.price = price;
    }

    public String getDetail() {
        return detail;
    }

    public void setDetail(String detail) {
        this.detail = detail;
    }

    public String getPic() {
        return pic;
    }

    public void setPic(String pic) {
        this.pic = pic;
    }

    public Timestamp getCreatetime() {
        return createtime;
    }

    public void setCreatetime(Timestamp createtime) {
        this.createtime = createtime;
    }
}

Mybatis的缓存机制

在这里插入图片描述
增删改都要提交事务就会刷新缓存
如果开启两个会话进行查询相同的内容,如果第一个会话先结束了,第二个会话再进行查询,查询的结果就是相同对象,也就是第一个会话查询之后产生缓存,第二个会话在第一个会话结束后进行查询的就是缓存中的东西

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值