mybatis系列:一、简单入门

mybatis 的简单概述

  • mybatis 本是 apache 的一个开源项目 iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
  • mybatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。
  • mybatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录。

原生 jdbc 的问题

  • 数据库的频繁连接、释放造成资源浪费,影响系统性能(使用数据库连接池来解决此问题)
  • sql语句的多变化造成代码变化,不易维护
  • sql语句使用硬编码,不易维护
  • 对结果集的解析也存在硬编码,不易维护

mybatis 架构解析

在这里插入图片描述

  • mybatis 配置
    • SqlMapConfig.xml
      mybatis 全局配置文件,配置mybatis的运行环境等信息
    • mapper.xml
      sql 映射文件,配置操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载
  • 通过mybatis配置信息构造SqlSessionFactory,即会话工厂
  • 通过会话工厂SqlSessionFactory创建会话SqlSession
  • mybatis底层自定义了Executor执行器接口来操作数据库,Executor接口有2个实现:基本执行器、缓存执行器
  • Mapped Statement也是mybatis底层的一个封装对象,它包装了mybatis的配置信息和sql的映射信息。mapper.xml文件中的一个sql对应一个Mapped Statement,sql的id也即Mapped Statement的id
    • Mapped Statement对sql的执行参数进行了定义。Executor通过Mapped Statement在执行sql前将java对象映射到sql中
    • Mapped Statement对sql的执行结果也进行了定义。Executor通过Mapped Statement在执行结果映射到java对象中。

mybatis 入门程序

  • 引入jar包
  • 配置log4j.properties
    mybatis 默认使用log4j来输出日志信息
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
  • 配置 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>
    <!-- 与spring整合之后,environments将被废除 -->
    <environments default="development">
        <!-- 可以配置多个环境 -->
        <environment id="development">
            <!-- 使用JDBC事务管理 -->
            <transactionManager type="JDBC"/>
            <!-- 数据库连接池,使用mybatis自带的连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf-8" />
                <property name="username" value="username" />
                <property name="password" value="password" />
            </dataSource>
        </environment>
    </environments>

    <!-- 加载mapper.xml -->
    <mappers>
        <!-- 指定classpath下的文件 -->
        <mapper resource="sqlmap/User.xml"/>
    </mappers>
</configuration>
  • 配置 sqlmap/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">

<!-- namespace命名空间的作用是为了更好的对sql进行隔离和管理 -->
<mapper namespace="test">

    <!-- 查询 #{}:就相当于一个占位符;如果parameterType传入的是简单类型的值,{}中可以使用value或者其他任意字符,目的是防止sql注入 -->
    <select id="findUserById" parameterType="int" resultType="cn.ade.mybatis.po.User">
        SELECT * FROM user WHERE id = #{id}
    </select>

    <!-- 查询 ${}:就相当于一个拼接符;如果parameterType传入的是简单类型的值,{}中只能使用value -->
    <select id="findUserByUsername" parameterType="string" resultType="cn.ade.mybatis.po.User">
        SELECT * FROM user WHERE username LIKE "%${value}%"
    </select>

	<!-- 新增 -->
	<insert id="insertUser" parameterType="cn.ade.mybatis.po.User">
        <selectKey keyProperty="id" order="AFTER" resultType="int">
            SELECT LAST_INSERT_ID()
        </selectKey>
        INSERT INTO user VALUES (null, #{username},#{birthday},#{sex},#{address})
    </insert>
</mapper>
  • 在 SqlMapConfig.xml 中配置 mappers
    配置见如上
  • 测试程序
public class TestDemo01 {

    /** 会话工厂 */
    private SqlSessionFactory factory;

    @Before
    public void createSqlSessionFactory() throws IOException {
        // mybatis全局配置文件
        String resource = "SqlMapConfig.xml";

        // 构造全局配置文件的输入流
        InputStream inputStream = Resources.getResourceAsStream(resource);

        // 创建SqlSessionFactory会话工厂
        factory = new SqlSessionFactoryBuilder().build(inputStream);
    }

    @Test
    public void findUserById() throws IOException {
        // 创建session会话
        SqlSession session = factory.openSession();

        // 根据session查询用户
        User user = session.selectOne("test.findUserById", 1);
        System.out.println(user);

        // 关闭session
        session.close();
    }

    @Test
    public void findUserByUsername() throws IOException {
        // 创建会话
        SqlSession session = factory.openSession();

        // 根据session查询用户
        List<User> users = session.selectList("test.findUserByUsername", "五");
        System.out.println(users);

        // 关闭会话
        session.close();
    }
	
	@Test
    public void insertUser() throws IOException {
        // 创建会话
        SqlSession session = factory.openSession();

        // 添加用户
        User user = new User();
        user.setUsername("张三");
        user.setSex("10");
        user.setBirthday(new Date());
        user.setAddress("西安");

        session.insert("test.insertUser", user);
        System.out.println(user.getId());

        // 提交事务
        session.commit();

        // 关闭会话
        session.close();
    }
    
}

案例总结

主键问题

  • mysql 的主键自增
<!-- 新增 -->
<insert id="insertUser" parameterType="cn.ade.mybatis.po.User">
    <selectKey keyProperty="id" order="AFTER" resultType="int">
        SELECT LAST_INSERT_ID()
    </selectKey>
    INSERT INTO user VALUES (null, #{username},#{birthday},#{sex},#{address})
</insert>

keyProperty:返回的主键存储在哪个属性中
order:selectKey的执行顺序
LAST_INSERT_ID():mysql的函数,返回自增列新记录的id值

  • oracle 的主键自增
<!-- 新增 -->
<insert id="insertUser" parameterType="cn.ade.mybatis.po.User">
    <selectKey keyProperty="id" order="BEFORE" resultType="java.lang.Integer">
        SELECT 自定义序列.NEXTVAL FROM DUAL
    </selectKey>
    INSERT INTO user VALUES (null, #{username},#{birthday},#{sex},#{address})
</insert>
  • mysql 的uuid
<!-- 新增 -->
<insert id="insertUser" parameterType="cn.ade.mybatis.po.User">
    <selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
        select uuid()
    </selectKey>
    INSERT INTO user VALUES (null, #{username},#{birthday},#{sex},#{address})
</insert>

#{} 和 ${} 的区别

#{}表示一个占位符号,通过#{}可以实现parameterType向占位符中设置值,自动进行java类型和jdbc类型转换
#{}可以有效防止sql注入。
#{}可以接收简单类型值或pojo属性值。
如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。

${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换
${}可以接收简单类型值或pojo属性值,
如果parameterType传输单个简单类型值,${}括号中只能是value

selectOne 和 selectList

  • selectOne查询一条记录,如果使用selectOne查询多条记录则抛出异常
  • selectList可以查询一条或多条记录

mybatis 解决 jdbc 编程的问题

  • 在SqlMapConfig.xml中配置数据连接池,使用连接池管理数据库连接
  • 将sql语句配置在mapper.xml文件中与java代码分离
  • mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型
  • mybatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型

与hibernate的区别

相同点:

hibernate与mybaits都可以是通过SessionFactoryBuider由XML配置文件生成SessionFactory,然后由SessionFactory 生成Session,最后由Session来开启执行事务和SQL语句。
其中SessionFactoryBuider,SessionFactory,Session的生命周期都是差不多的。
hibernate和mybaits都支持JDBC和JTA事务处理。

不同点:

hibernate是全自动,而mybatis是半自动
hibernate数据库移植性远大于mybatis
hibernate拥有完整的日志系统,mybatis则欠缺一些
mybatis相比hibernate需要关心很多细节
sql直接优化上,mybatis要比hibernate方便很多
缓存机制上,hibernate要比mybatis更好一些

发布了48 篇原创文章 · 获赞 1 · 访问量 1044

猜你喜欢

转载自blog.csdn.net/laonxs/article/details/105105736