mybatis

一.基本认识

  • mybatis是一个ORM框架
  • ORM:对象关系映射
  • mybatis对jdbc的重复代码进行了封装,依然需要自己写sql(比jdbc开发快,比jpa性能好)

二.hello,mybatis

2.1 导包

  • mybatis核心包 mybatis/mybatis-3.2.1.jar
  • mybatis的依赖包 mybatis/lib/*.jar
  • jdbc驱动包 mysql-connector-java-5.1.26-bin.jar

2.2 基本准备(表,domain)

  • 库(mybatis) -> 表(product)【导入-resources准备sql脚本product.sql】
  • Product对象
 public class Product {
    private Long id;
    //产品名称
    private String productName;
    //成本价
    private Double costPrice;
    //销售价格
    private Double salePrice;
    //供应商
    private String supplier;
    //品牌
    private String brand;
    //折扣
    private Double cutoff;
    //产品类型
    private Long dir_id;
    //省略getter,setter与toString...
}

2.3 创建配置文件

配置文件的位置要注意

  • 注:配置文件的代码可以去找:网上,官方文档,官方中文文档
  • 官方中文文档 : doc/mybatis-3.2.1.pdf

image

jdbc.properties:数据库的参数

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

mybatis-config.xml:mybatis的核心配置

<?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:配置(xml的一个根)-->
<configuration>
    <!--引入jdbc.propeties文件-->
    <properties resource="jdbc.properties" />
    <!--
        environments:环境(多个环境)
            default="development":多个环境中默认使用的是哪一个环境
    -->
    <environments default="development">
        <!--
             environment:某一个环境 id:就是这个环境的名称
        -->
        <environment id="development">
            <!--
                transactionManager:事务管理(ACID)
                    type="JDBC|MANAGED" jdbc:简单jdbc事务 MANAGED:啥都不做
            -->
            <transactionManager type="JDBC"/>
            <!-- 数据源(连接池) POOLED:mybatis内置的连接池 -->
            <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>
    <mappers>
        <!--引入(找到)写SQL的XML-->
        <mapper resource="cn/itsource/dao/ProductMapper.xml"/>
    </mappers>
</configuration>

ProductMapper.xml:sql语句

<?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:根(每个xml都得有,不用管它的含义)
        namespace:命名空间(随便取个名称)
-->
<mapper namespace="cn.itsource.dao.ProductMapper">
    <!--
        select:代表这是一个查询语句
            id:代表这个查询语句的唯一命名
                以后你要找到这条SQL: namespace+id
                例:cn.itsource.dao.ProductMapper.getOne
            parameterType:参数类型
                long -> Long  _long -> long
            resultType:返回的每一条结果的类型
                注:返回类型的全限定名
    -->
    <select id="getOne" parameterType="long" resultType="cn.itsource.domain.Product">
        select * from product where id = #{id}
    </select>

</mapper>

2.4 测试

  1. 读取核心配置文件
  2. 获取SqlSession对象 SqlSessionFactoryBuilder -> SqlSessionFactory -> SqlSession
  3. 执行查询
/**
 * ①. 想办法搞到核心配置文件 mybatis-config.xml
 * ②. 获取到它的核心对象 SqlSession【相当于是咱们JPA中的EntityManager对象】
 *          EntityManagerFactory -> EntityManager
 *          SqlSessionFactoryBuilder -> SqlSessionFactory -> SqlSession
 *  ③.SqlSession就可以CRUD..
 */
@Test
public void testHello() throws Exception{
    //①. 想办法搞到核心配置文件 mybatis-config.xml
    Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
    //②.获取到它的核心对象 SqlSession
    // 2.1获到到SqlSessionFactory对象
    SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    SqlSessionFactory factory = builder.build(reader);
    // 2.2获取到它的核心对象 SqlSession
    SqlSession session = factory.openSession();

    //③.获取到一个对象
    /**
     * String statement : 获取SQL的字符串 namespace+id
     * Object parameter : 参数传递
     */
    Product product = session.selectOne("cn.itsource.dao.ProductMapper.getOne",1L);
    System.out.println(product);

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

三.工具类与CRUD

3.1 准备MyBatisUtil

  • SqlSessionFactoryBuilder:只用于创建factory,用完就可以扔掉
  • SqlSessionFactory:重级量对象,创建后不要随便销毁(一个项目一个这个对象即可)
  • SqlSession :用于完成咱们的CRUD
/**
 * MyBatis的工具类,主要就是为我们创建SqlSession对象
 */
public class MyBatisUtil {
    //定义一个SqlSessionFactory对象
    /**
     * 一个对象写这个位置,而且是静态的,它是有线程安全问题的
     */
    private static SqlSessionFactory factory = null;

    /**
     * SqlSessionFactoryBuilder:唯一的作用就是创建SqlSessionFactory
     *      一旦用完就可以把它把抛弃了
     * 1.类加载的时候就会执行
     * 2.只会执行一次
     */
    static {
        try {
            factory = new SqlSessionFactoryBuilder().build(
                    Resources.getResourceAsReader("mybatis-config.xml")
            );
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static SqlSession openSession(){
        return factory.openSession();
    }

}

3.1 完成CRUD

3.1.1 productMapper.xml

<!--
    select:代表这是一个查询语句
        id:代表这个查询语句的唯一命名
            以后你要找到这条SQL: namespace+id
            例:cn.itsource.dao.ProductMapper.getOne
        parameterType:参数类型
            long -> Long  _long -> long
        resultType:返回的每一条结果的类型
            注:返回类型的全限定名
-->
<select id="getOne" parameterType="long" resultType="product">
    select * from product where id = #{id}
</select>

<!--resultType:返回的每一条结果的类型-->
<select id="getAll" resultType="product" >
    select * from product
</select>

<!--
    添加一条数据
        useGeneratedKeys:是否要主键
        keyColumn="id":在数据库中名称叫id
        keyProperty="id":在类中也叫id
        主键会放到你传过来的对象中
-->
<insert id="save" parameterType="product"
        useGeneratedKeys="true" keyColumn="id" keyProperty="id">
  insert into product
  (productName,dir_id,salePrice,supplier,brand,cutoff,costPrice) values
  (#{productName},#{dir_id},#{salePrice},#{supplier},#{brand},#{cutoff},#{costPrice})
</insert>

<!--修改功能-->
<update id="update" parameterType="product">
    update product set
        productName=#{productName},
        dir_id=#{dir_id},
        salePrice=#{salePrice},
        supplier=#{supplier},
        brand=#{brand},
        cutoff=#{cutoff},
        costPrice=#{costPrice}
        where id=#{id}
</update>

<!-- 删除功能 -->
<delete id="delete" parameterType="long">
    delete from product where id=#{id}
</delete>

3.1.1 productDao中完成功能

  • 增删改需要提交事务
package cn.itsource.dao.impl;

import cn.itsource.dao.IProductDao;
import cn.itsource.domain.Product;
import cn.itsource.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;

import java.util.List;

public class ProductDaoImpl implements IProductDao {

    private final String NAMESPACE = "cn.itsource.dao.ProductMapper.";
    @Override
    public void save(Product product) {
        SqlSession session = null;
        try {
            session = MyBatisUtil.openSession();
            session.insert(NAMESPACE+"save",product);
            //提交事务
            session.commit();
        } catch (Exception e) {
            //回滚事务
            session.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }
    }

    @Override
    public void update(Product product) {
        SqlSession session = null;
        try {
            session = MyBatisUtil.openSession();
            session.update(NAMESPACE+"update",product);
            //提交事务
            session.commit();
        } catch (Exception e) {
            //回滚事务
            session.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }
    }

    @Override
    public void delete(Long id) {
        SqlSession session = null;
        try {
            session = MyBatisUtil.openSession();
            session.delete(NAMESPACE+"delete",id);
            //提交事务
            session.commit();
        } catch (Exception e) {
            //回滚事务
            session.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }
    }

    @Override
    public Product getOne(Long id) {
        SqlSession session = null;
        try {
            session = MyBatisUtil.openSession();
            return session.selectOne(NAMESPACE+"getOne",id);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            session.close();
        }
        return null;
    }

    @Override
    public List<Product> getAll() {
        SqlSession session = null;
        try {
            session = MyBatisUtil.openSession();
            return session.selectList(NAMESPACE+"getAll");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            session.close();
        }
        return null;
    }
}

四.细节处理

4.1 添加的对象返回id

  • useGeneratedKeys:是否要使用主键
  • keyColumn="id":在数据库中名称叫id
  • keyProperty="id":在类中主键的名称id
  • 主键会放到你传过来的对象中
<!--
    添加一条数据
-->
<insert id="save" parameterType="product"
        useGeneratedKeys="true" keyColumn="id" keyProperty="id">
  insert into product
  (productName,dir_id,salePrice,supplier,brand,cutoff,costPrice) values
  (#{productName},#{dir_id},#{salePrice},#{supplier},#{brand},#{cutoff},#{costPrice})
</insert>

4.2 别名的配置

  • 内置别名(int,long,..)/自定义别名(自己的类)
  • 别名不区分大小写
  • 自定义别名的配置
    • 每个对象单独配置别名 <typeAlias type="cn.itsource.domain.Product" alias="Product" />
    • 扫描包(这个包的对象都会取别名) <package name="cn.itsource.domain" />
<?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:配置(xml的一个根)-->
<configuration>
    <!--引入jdbc.propeties文件-->
    <properties resource="jdbc.properties" />
    <!--
        typeAliases:配置别名
            注:别名不区别大小写
    -->
    <typeAliases>
        <!-- type:类型   alias:别名-->
        <!--<typeAlias type="cn.itsource.domain.Product" alias="Product" />-->
        <!--为这个包下面的所有类取别名(就是类名)-->
        <package name="cn.itsource.domain" />
        <package name="cn.itsource.query" />
    </typeAliases>
    <environments default="development">
       ...
    </environments>
    <mappers>
       ...
    </mappers>
</configuration>

4.3 日志的处理

  • mybatis中是使用日志来显示sql的
  • 在资源根目录创建一个log4j.properties
# ERROR错误的日志 WARN:警告 INFO:普通信息  DEBUG:调试日志  TRACE:日志
log4j.rootLogger=ERROR, stdout
#log4j.rootLogger=NONE
#把左边包名改成你自己的包名
log4j.logger.cn.itsource=TRACE
# 日志打印到控制台中
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
# 日志打印的一种格式(可以灵活地指定布局模式)
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# 日志打印的格式是什么样子的  %d:日期 %p:优先级 %c:类的全名  %m:输出的结果 %n:换行
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n

4.4 #与$的区别(面试题)

  • $只能从对象中取属性(getter属性)
  • #支持预编译方案(性能更好,安全性更高)
  • 优先使用#,有些拼接字符串的地方不支持,再使用$

五.批量操作与动态SQL

5.1 批量添加

  • sql: insert into 表名 (列名,列名) values (?,?),(?,?),...
  • 实现使用foreach
<!--
    批量添加
     insert into employee (name,age,sex) values
             ("小小良",45,false),("大二良",45,true)
    foreach:循环
        collection:遍历的集合
        item:每次遍历拿到的对象
        separator:分隔符(每个值都使用,隔开)
-->
<insert id="batchSave" parameterType="list">
    insert into employee (name,age,sex) values
    <foreach collection="list" item="e" separator=",">
        (#{e.name},#{e.age},#{e.sex})
    </foreach>
</insert>

5.2 批量删除

  • sql: delete from 表名 where id in(?,?,..)
  • 实现使用foreach
<!--
    批量删除:DELETE FROM employee WHERE id in (?,?,?,...)
    传 : List<Long> ids
     foreach:循环
        collection:遍历的集合
        item:每次遍历拿到的对象
        separator:分隔符(每个值都使用,隔开)
        open:以什么开头
        close:以什么结尾
        index:遍历的索引
-->
<delete id="batchDelete" parameterType="list">
  delete from employee where  id in
  <foreach collection="list" item="id" separator="," open="(" close=")">
      #{id}
  </foreach>
</delete>

5.3 动态修改

  • 解决咱们以前的数据丢失问题
  • 对象中没有值就不做修改
<!--
        动态修改:只修改有值的数据
-->
<update id="dynamicUpdate" parameterType="employee">
    update employee
    <set>
        <if test="name!=null">
            name=#{name},
        </if>
        <if test="age!=null">
            age=#{age},
        </if>
        <if test="sex!=null">
            sex=#{sex},
        </if>
    </set>
    where id=#{id}
</update>

今日扩展

连接池

比较流行的连接池有三个

  • Spring建议使用的DBCP
  • Hibernate建议使用的C3P0
  • 阿里连接池 druid -> 现在外面用得还是比较多

mysql的数据库引擎

  • InnoDB : 支持事务,支持外键
  • MyISAM : 不支持事务,不支持外键(速度快)
原文地址:https://www.cnblogs.com/13438145925xiaozheng/p/11380932.html