01-Mybatis 入门

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/my_momo_csdn/article/details/91042270

MyBatis入门

一、ORM和JDBC对比

JDBC ORM
编程复杂 相对简单
需要手动关闭连接 引入连接池,不需要手动关闭
业务与技术代码耦合 代码解耦

二、MyBatis和Hibernate对比

MyBatis Hibernate
半自动ORM框架 全自动ORM框架
高度灵活,必须写SQL 全表映射不方便,无法自定义组装SQL,不要写SQL
基于SQL优化方便 HQL黑盒封装,调优复杂
开发人员自定义SQL 复杂SQL支持若
性能好 性能相对低

三、MyBatis三要素

  • POJO:Java实体类
  • 映射规则:每一个Java接口对应一个xml文件,接口文件中方法对应xml中的一个节点,节点内包含sql语句和映射规则
  • SQL语句:对接数据库

四、MyBatis核心类引入

  • SqlSessionFactoryBuilder:通过建造者模式,辅助构建SqlSessionFactory对象
  • SqlSessionFactory:创建SqlSession的工厂,单例模式,存在与整个程序的生命周期
  • SqlSession:代表一次数据库链接,线程不安全,需要线程独享(方法级),具备执行sql的能力
  • SQL Mapper:由java接口文件和Xml文件组成,包含需要执行上午sql语句和结果集映射,方法级别生命周期,一次SqlSession可能会访问多次数据库。

五、入门案例

5.1 Maven依赖

         <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.19</version>
        </dependency>

        <!-- mybatis相关依赖 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.1-moping</version>
        </dependency>

5.2 创建属性文件

  • 使用属性文件db.properties保存数据库配置,然后再MyBatis的主配置文件引入该文件,保存在resources目录下面
jdbc_driver=com.mysql.jdbc.Driver
jdbc_url=jdbc:mysql://192.168.11.27:3306/demo?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true
jdbc_username=root
jdbc_password=introcks1234

5.3 创建MyBatis配置文件

  • MyBatis主配置文件mybatis-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>

    <!--引入属性文件-->
    <properties resource="db.properties"/>
    
    <!--配置environment环境 -->
    <environments default="development">
        <!-- 环境配置1,每个SqlSessionFactory对应一个环境 -->
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc_driver}"/>
                <property name="url" value="${jdbc_url}"/>
                <property name="username" value="${jdbc_username}"/>
                <property name="password" value="${jdbc_password}"/>
            </dataSource>
        </environment>
    </environments>

    <!-- 映射文件,mapper的配置文件 -->
    <mappers>
        <!--直接映射到相应的mapper文件 -->
        <mapper resource="mybatis/mapper/ItemMapper.xml"/>
    </mappers>

</configuration>

5.4 创建xml映射文件

  • ItemMapper.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="item">

    <insert id="addItem" parameterType="com.intellif.mozping.entity.Item">
		insert into tb_item(id,description)values(#{id},#{description})
	</insert>


    <delete id="deleteItemById" parameterType="java.lang.Integer">
        DELETE  FROM tb_item where id = #{id}
    </delete>

    <update id="updateItemById" parameterType="com.intellif.mozping.entity.Item">
      UPDATE  tb_item set description=#{description} where  id = #{id}
    </update>

    <select id="findItemById" resultType="com.intellif.mozping.entity.Item" parameterType="java.lang.Integer">
        SELECT * FROM tb_item where id = #{id};
    </select>

</mapper>

5.5 测试

  • 注意这里的测试还没有和Java接口文件有任何关系,我们获取sqlsession之后,直接通过
    SqlSession来调用xml映射文件里面的sql语句,sqlSession.insert方法的第一个参数就是定位xml文件中sql语句,第二个参数就是调用Sql的传参,因此我们看到其实MyBatis在没有Java接口文件的情况下是可以直接通过映射文件操作数据库的,而这就是ibatis的编程模式,mybatis只是基于此增加了java接口,使得我们可以面向接口编程,在有Java接口文件的情况下无非就是根据接口方法名去找xml中的Sql而已,默认我们在Java接口文件中的方法名和xml中的id是要一致的。
@Data
public class Item {
    private int id;
    private String description;
}

public class Test01 {

    @Test
    public void add() throws IOException {
        String resource = "mybatis/mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        // 1.读取mybatis配置文件创SqlSessionFactory
        SqlSession sqlSession = new SqlSessionFactoryBuilder().build(inputStream).openSession();

        Item item = new Item();
        item.setId(1);
        item.setDescription("No 1");
        
        int rowAffected = sqlSession.insert("item.addItem", item);
        System.out.println("The rows be affected :" + rowAffected);
        //显示提交事务
        sqlSession.commit();
        sqlSession.close();
    }
}

打印:The rows be affected :1
数据库也有新记录插入。

5.6 优化

  • SqlSessionFactory在程序生命周期中是单例的,因此可以抽取出来
public class SqlSessionFactoryUtil {

    private static SqlSessionFactory factory;

    public static SqlSessionFactory getSqlSessionFactoryInstace() {
        if (factory == null) {
            InputStream in = null;
            try {
                in = Resources.getResourceAsStream("mybatis/mybatis-config.xml");
            } catch (Exception e) {
                e.printStackTrace();
            }
            synchronized (SqlSessionFactoryUtil.class) {
                if (factory == null) {
                    factory = new SqlSessionFactoryBuilder().build(in);
                }
            }
        }
        return factory;
    }
}

5.7 完整增删改查

public class Test01 {

    @Test
    public void add() {
        SqlSession sqlSession = SqlSessionFactoryUtil.getSqlSessionFactoryInstace().openSession();
        Item item = new Item();
        item.setId(1);
        item.setDescription("No 1");
        int rowAffected = sqlSession.insert("item.addItem", item);
        System.out.println("The rows be affected :" + rowAffected);
        //显示提交事务
        sqlSession.commit();
        sqlSession.close();
    }

    @Test
    public void query() {
        SqlSession sqlSession = SqlSessionFactoryUtil.getSqlSessionFactoryInstace().openSession();
        List<Object> list = sqlSession.selectList("item.findItemById", 1);
        for (Object obj : list) {
            System.out.println(((Item) obj).toString());
        }
    }

    @Test
    public void update() {
        SqlSession sqlSession = SqlSessionFactoryUtil.getSqlSessionFactoryInstace().openSession();
        Item item = new Item();
        item.setId(1);
        item.setDescription("No 1 be updated");
        int rowAffected = sqlSession.update("item.updateItemById", item);
        System.out.println("The rows be affected :" + rowAffected);
        //显示提交事务
        sqlSession.commit();
        sqlSession.close();
    }

    @Test
    public void delete() {
        SqlSession sqlSession = SqlSessionFactoryUtil.getSqlSessionFactoryInstace().openSession();
        int rowAffected = sqlSession.delete("item.deleteItemById", 1);
        System.out.println("The rows be affected :" + rowAffected);
        //显示提交事务
        sqlSession.commit();
        sqlSession.close();
    }

}

5.8 使用代理的方式访问

  • 在之前我们小结了,我们没有和Java接口有任何的关系,我们直接就是使用Mybatis加载它的主配置文件,在主配置文件中配置了xml映射文件,然后获得了sqlsession之后,我们就可以通过xml中的id和namespace来访问调用里面的sql语句了。相当于是sqlsession —> xml —> DB
    但是我们一般是通过Java接口来使用的,而且通常我们在Java中的接口名字和xml中的id是保持一致的,这个过程是如何实现的,具体深层原理我们暂时无法捋清楚,但是底层其实是使用了动态代理,这里手动使用动态代理来做一次数据库的访问(如果我们做到了通过接口访问数据库,里面使用动态代理技术,那么实际上这里看起来就像是已经做到了mybatis框架所做的事情,而mybatis实际上就是这么干的)。

5.8.1 创建Java接口

public interface ItemMapper {

    int addItem(Item item);

    int deleteItemById(int id);

    int updateItemById(Item item);

    List<Object> findItemById(int id);

}

5.8.2 通过Java接口访问数据库

    @Test
    public void addInterface() {
        SqlSession sqlSession = SqlSessionFactoryUtil.getSqlSessionFactoryInstace().openSession();
        Item item = new Item();
        item.setId(1);
        item.setDescription("No 1");
        ItemMapper mapper = sqlSession.getMapper(ItemMapper.class);
        int rowAffected =  mapper.addItem(item);
        System.out.println("The rows be affected :" + rowAffected);
        //显示提交事务
        sqlSession.commit();
        sqlSession.close();
    }
    验证保存数据成功,但是这里注意需要将xml中的命名空间修改一下,前面是item,这里需要修改为ItemMapper的全类名:
    com.intellif.mozping.dao.ItemMapper

5.8.3 自己通过代理方式

  • 下面代码中,我们通过动态代理生产一个ItemMapper接口对象,这个对象调用addItem方法,但是实际上底层,我们是通过动态代理
    对象来真正的访问数据库的,我们获得了mapper.addItem这个方法的全限定名称,实际上就是xml文件中的namespace+id,通过这个来调用,是不是又回到了之前的sqlsession的最原始的不需要Java接口的工作方式,调用方式和前面的add都是一模一样的,这样我们就可以简单的通过接口来访问数据库了。而实际上MyBatis框架就是按照这样的思想来做的,程序员面向接口编程,调用接口中的方法,底层通过动态代理创建了代理对象去真正的访问数据库,通过接口方法Mybatis会知道你想调用xml中的哪一个sql,然后让代理对象去做,底层还是sqlsession在做一系列的事情,但是却简化了编程的工作,对于单纯的使用,我们甚至可以不care sqlsession的存在。
@Test
    public void proxyMybatis() {
        ItemMapper mapper = (ItemMapper) Proxy.newProxyInstance(ItemMapper.class.getClassLoader()
                , new Class[]{ItemMapper.class}, new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println(ItemMapper.class.getName() + "." + method.getName());
                        Object obj = null;
                        for (Object object : args) {
                            System.out.println(object);
                            obj = object;
                        }

                        // 实现逻辑
                        SqlSession sqlSession = SqlSessionFactoryUtil.getSqlSessionFactoryInstace().openSession();
                        int result = sqlSession.insert(ItemMapper.class.getName() + "." + method.getName(), obj);

                        //显示提交事务
                        sqlSession.commit();
                        sqlSession.close();
                        return result;
                    }
                });

        Item item = new Item();
        item.setId(1);
        item.setDescription("No 1");

        int rowAffected = mapper.addItem(item);

    }
  • 对比动态代理方式的实现代码和通过Java接口访问数据库的代码,我们完全可以把创建代理对象的代码和下面的代码等价起来
    ,我们看到前后的代码都是一致的,我们可以这样理解sqlSession.getMapper(ItemMapper.class)其实就是创建了一个ItemMapper
    类型的代理对象,后期通过mapper.addItem的方式访问数据库,其实都是代理对象去做的,代理对象通过方法名找到xml中的sql来执行。如果再结合Spring,通过注解实现代理对象的创建并交给IOC容器去管理,那么将大大简化代码。
ItemMapper mapper = sqlSession.getMapper(ItemMapper.class);

5.8.4 注意事项

  • 在使用Java接口的方式访问数据库我们也发现了几点需要注意的地方
序号 注意点
1 接口方法的全限定名称必须和xml中的namespace+id保持一致,接口类名对应namespace,方法名对应id
2 映射文件的名称必须和接口的名称一致,映射文件是XXX.xml,接口文件是XXX.java

六、小结

  • 我们首先通过简单的入门案例了解了mybatis的使用,在测试代码中我们用ibatis的编程方式来访问数据库,然后使用动态代理实现了使用接口访问数据库,而mybatis做
    的工作就是基于ibatis的方式,让程序员可以面向接口编程,其底层也是使用动态代理来实现,这些细节我们在后循序渐进的学习。

猜你喜欢

转载自blog.csdn.net/my_momo_csdn/article/details/91042270
今日推荐