mybatis

作者: vincent519 | 来源:发表于2019-10-08 14:23 被阅读0次

    mybatis


    1.如何批量插入数据

    SQL层面

    先复习一下单条/批量插入数据的sql语句怎么写:

    1. 单条插入数据的写法:

    INSERT INTO [表名]

    ([列名],[列名])

    VALUES

    ([列值],[列值]))

    2.一次性批量插入数据的sql语句的写法:

    INSERT INTO [表名]

    ([列名],[列名])

    VALUES

    ([列值],[列值])),

    ([列值],[列值])),

    ([列值],[列值]));

    批量的好处:可以避免程序和数据库建立多次连接,从而增加服务器负荷。

    MyBatis层面如何完成批量插入

    MyBatis批量插入数据到数据库有两种方式:xml文件,注解,这里使用MySQL。

    方法一:xml配置

    最基础的是用mapping.xml配置的方式,包括以下两种具体方式:

    1. mapping.xml中insert语句可以写成单条插入,在调用方循环1000次

    <!-- 在外部for循环调用1000次 -->

    <insert id="insert" parameterType="sdc.mybatis.test.Student">

    insert into student (id, name, sex,

    address, telephone, t_id

    )

    values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR},

    #{sex,jdbcType=VARCHAR},

    #{address,jdbcType=VARCHAR}, #{telephone,jdbcType=VARCHAR}, #{tId,jdbcType=INTEGER}

    )

    </insert>

    2. mapping.xml中insert语句写成一次性插入一个1000的list

    mapping.xml

    <insert id="insertBatch" >

    insert into student ( <include refid="Base_Column_List" /> )

    values

    <foreach collection="list" item="item" index="index" separator=",">

    (null,#{item.name},#{item.sex},#{item.address},#{item.telephone},#{item.tId})

    </foreach>

    </insert>

    参数解释:

    collection:指定要遍历的集合;

    表示传入过来的参数的数据类型。该参数为必选。要做 foreach 的对象,作为入参时,List 对象默认用 list 代替作为键,数组对象有 array 代替作为键,Map 对象没有默认的键;

    item:将当前遍历出的元素赋值给指定的变量,然后用#{变量名},就能取出变量的值,也就是当前遍历出的元素;

    index:索引,遍历list的时候index就是索引,遍历map的时候index表示的就是map的key,item就是map的值;

    separator:每个元素之间的分隔符, select * from Emp where id in(1,2,3)相当于1,2,3之间的","

    mapper接口中的使用:

    public interface EmpMapper {

    public List<Emp> getEmpsByConditionLike(@Param("list")List<Integer> ids);

    }

    方法二:注解

    注解说明:

    MyBatis提供用于插入数据的注解有两个:@insert,@InsertProvider,类似还有:@DeleteProvider@UpdateProvider和@SelectProvider;

    作用:

    用来在实体类的Mapper类里注解保存方法的SQL语句

    区别:

    @Insert是直接配置SQL语句,而@InsertProvider则是通过SQL工厂类及对应的方法生成SQL语句,这种方法的好处在于,我们可以根据不同的需求生产出不同的SQL,适用性更好。

    使用:

    @Insert

    @Insert("insert into blog(blogId,title,author) values(#blogId,#title,#author)")

    public boolean saveBlog(Blog blog);

    @InsertProvider

    在mapper接口中的方法上使用@InsertProvider注解:

    @InsertProvider(type=ActivationProvider.class, method="insertAll")

    boolean insertAll(@Param("list") List<String> codeArray);

    参数解释:

    type为工厂类的类对象,method为对应的工厂类中的方法,方法中的@Param("list")是因为批量插入传入的是一个list,但是Mybatis会将其包装成一个map,其中map的key为"list",value为传入的list。

    工厂类ActivationProvider中的方法:

    首先要map.get方法得到对应的list;

    然后拼接insert语句,要生成的正确的sql语句的格式为:

    INSERT INTO User (id, name) VALUES (null, #{list[0].name}), (null, #{list[1].name})[,(null, #{list[i].name})]

    其中list[0]代表list中第0个元素

    特别注意:

    一定注意:注意Mapper到Provider参数类型的变化(List --> Map),Mapper中传入的List会被包裹在一个Map中传给Provider,而key就是在Mapper的@Param注解中指定的名称(默认为list)。在Provider方法中使用List<T> list = (List<T>) map.get(key);即可拿到我们传入的List。

    否则会报错:

    Caused by: org.apache.ibatis.binding.BindingException: Parameter 'arg0' not found. Available parameters are [1, 0, param1, param2]

    xml、注解方式区别:

    1.foreach相当语句逐条INSERT语句执行,将出现如下问题:

        a. mapper接口的isnert方法返回值将是最一条INSERT语句的操作成功的记录数目

        (就是0或1),而不是所有INSERT语句的操作成功的总记录数目。

        b. 当其中一条不成功时,不会进行整体回滚。

    2.注解方式:当有一条插入不成功时,会整体回滚


    2. foreach有什么关键字

    <foreach> 元素主要用在构建 in 条件中,它可以在 SQL 语句中迭代一个集合。

    <foreach> 元素的属性主要有 item、index、collection、open、separator、close。

    item 表示集合中每一个元素进行迭代时的别名。

    index 指定一个名字,用于表示在迭代过程中每次迭代到的位置。

    open 表示该语句以什么开始。

    separator 表示在每次进行迭代之间以什么符号作为分隔符。

    close 表示以什么结束。

    在使用 <foreach> 元素时,最关键、最容易出错的是collection属性,该属性是必选的,但在不同情况下该属性的值是不一样的,主要有以下3种情况:

    如果传入的是单参数且参数类型是一个List,collection属性值为list。

    如果传入的是单参数且参数类型是一个array数组,collection的属性值为array。

    如果传入的参数是多个,需要把它们封装成一个Map,当然单参数也可以封装成Map。Map的key是参数名,collection属性值是传入的List或array对象在自己封装的Map中的key。

    1)添加SQL映射语句

    在 com.mybatis 包的 UserMapper.xml 文件中添加如下 SQL 映射语句:

    <!--使用foreach元素查询用户信息-->

    <select id="selectUserByForeach" resultType="com.po.MyUser" parameterType=

    "List">

    select * from user where uid in

    <foreach item="item" index="index" collection="list"

    open="(" separator="," close=")">

    # {item}

    </foreach>

    </select>

    2)添加数据操作接口方法

    在 com.dao 包的 UserDao 接口中添加如下数据操作接口方法:

    public List<MyUser> selectUserByForeach(List<Integer> listId);

    3)调用数据操作接口方法

    在 com.controller 包的 UserController 类中添加如下程序调用数据操作接口方法。

    //使用foreach元素查询用户信息

    List<Integer> listId=new ArrayList<Integer>();

    listId.add(34);

    listId.add(37);

    List<MyUser> listByForeach = userDao.selectUserByForeach(listId);

    System.out.println ("foreach元素================");

    for(MyUser myUser : listByForeach) {

    System.out.println(myUser);

    }


    3.如何自增主键

    同一张student表,对于mysql,sql server,oracle中它们都是怎样创建主键的

    在mysql中

    create table Student(

    Student_ID int(6) NOT NULL PRIMARY KEY AUTO_INCREMENT,

    Student_Name varchar(10) NOT NULL,

    Student_Age int(2) NOT NULL

    );

    insert into student(student_name,student_age) values('zhangsan',20);

    在sql server中

    create table Student(

    Student_ID int primary key identity(1,1),

    Student_Name varchar2(10) NOT NULL,

    Student_Age number(2) NOT NULL

    );

    insert into student(student_name,student_age) values('zhangsan',20);

    在oracle中

    create table Student(

    Student_ID number(6) NOT NULL PRIMARY KEY,

    Student_Name varchar2(10) NOT NULL,

    Student_Age number(2) NOT NULL

    );

    oracle如果想设置主键自增长,则需要创建序列

    CREATE SEQUENCE student_sequence

    INCREMENT BY 1

    NOMAXVALUE

    NOCYCLE

    CACHE 10;

    insert into Student values(student_sequence.nextval,'aa',20);

    如果使用了触发器的话,就更简单了

    create or replace trigger student_trigger

    before insert on student

    for each row

    begin

    select student_sequence.nextval into :new.student_id from dual;

    end student_trigger;

    此时插入的时候触发器会帮你插入id

    insert into student(student_name,student_age) values('wangwu',20);

    至此,mysql,sql server,oracle中怎样创建表中的自增长主键都已完成。

    看一看出oracle的主键自增较mysql和sql sever要复杂些,mysql,sqlserver配置好主键之后,插入时,字段和值一一对应即可,数据库就会完成你想做的,但是在oracle由于多了序列的概念,如果不使用触发器,oracle怎样实现主键自增呢?

    <insert id="add" parameterType="Student">

      <selectKey keyProperty="student_id" resultType="int" order="BEFORE">

                select student_sequence.nextval from dual

            </selectKey>

          insert into student(student_id,student_name,student_age) values(#{student_id},#{student_name},#{student_age})

    </insert>

    或者

    <insert id="save" parameterType="com.threeti.to.ZoneTO" >

        <selectKey resultType="java.lang.Long" keyProperty="id" order="AFTER" >

            SELECT SEQ_ZONE.CURRVAL AS id from dual

        </selectKey>

        insert into TBL_ZONE (ID, NAME ) values (SEQ_ZONE.NEXTVAL, #{name,jdbcType=VARCHAR})

    </insert>


    4.如何使用in

    在SQL语法中如果我们想使用in的话直接可以像如下一样使用:

    select * from HealthCoupon where useType in ( '4' , '3' )

    但是如果在MyBatis中的使用in的话,像如下去做的话,肯定会报错:

    Map<String, Object> selectByUserId(@Param("useType") String useType)

    <select id="selectByUserId" resultMap="BaseResultMap" parameterType="java.lang.String">

      select * from HealthCoupon where useType in (#{useType,jdbcType=VARCHAR})

    </select>

    其中useType="2,3";这样的写法,看似很简单,但是MyBatis不支持。但是MyBatis中提供了foreach语句实现IN查询,foreach语法如下:

    foreach语句中, collection属性的参数类型可以是:List、数组、map集合

    collection: 必须跟mapper.java中@Param标签指定的元素名一样

    item: 表示在迭代过程中每一个元素的别名,可以随便起名,但是必须跟元素中的#{}里面的名称一样。

    index:表示在迭代过程中每次迭代到的位置(下标)

    open:前缀,sql语句中集合都必须用小括号()括起来

    close:后缀

    separator:分隔符,表示迭代时每个元素之间以什么分隔

    正确的写法有以下几种写法:

    (一)、selectByIdSet(List idList)

    如果参数的类型是List, 则在使用时,collection属性要必须指定为 list

    List<User> selectByIdSet(List idList);

    <select id="selectByIdSet" resultMap="BaseResultMap">

      SELECT  <include refid="Base_Column_List" />

      FROM t_user

      WHERE id IN

      <foreach collection="list" item="id" index="index" open="(" close=")" separator=",">

      #{id}

      </foreach>

    </select>

    (二)、List<User> selectByIdSet(String[] idList)

    如果参数的类型是Array,则在使用时,collection属性要必须指定为 array

    List<User> selectByIdSet(String[] idList);

    <select id="selectByIdSet" resultMap="BaseResultMap">

      SELECT

      <include refid="Base_Column_List" />

      FROM t_user

      WHERE id IN

      <foreach collection="array" item="id" index="index" open="(" close=")" separator=",">

      #{id}

      </foreach>

    </select>

    (三)、参数有多个时

    当查询的参数有多个时,有两种方式可以实现,一种是使用@Param("xxx")进行参数绑定,另一种可以通过Map来传参数。

    3.1 @Param("xxx")方式

    List<User> selectByIdSet(@Param("name")String name, @Param("ids")String[] idList);

    <select id="selectByIdSet" resultMap="BaseResultMap">

      SELECT

      <include refid="Base_Column_List" />

      FROM t_user

      WHERE name=#{name,jdbcType=VARCHAR} and id IN

      <foreach collection="idList" item="id" index="index"

          open="(" close=")" separator=",">

      #{id}

      </foreach>

    </select>

    3.2 Map方式

    Map<String, Object> params = new HashMap<String, Object>(2);

    params.put("name", name);

    params.put("idList", ids);

    mapper.selectByIdSet(params);

    <select id="selectByIdSet" resultMap="BaseResultMap">

    select

    <include refid="Base_Column_List" />

    from t_user where

    name = #{name}

    and ID in

    <foreach item="item" index="index" collection="idList" open="(" separator="," close=")">

    #{item}

    </foreach>

    </select>


    相关文章

      网友评论

        本文标题:mybatis

        本文链接:https://www.haomeiwen.com/subject/limsyctx.html