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次
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}
)
2. mapping.xml中insert语句写成一次性插入一个1000的list
mapping.xml
insert into student (
values
<foreach collection="list" item="item" index="index" separator=",">
(null,#{item.name},#{item.sex},#{item.address},#{item.telephone},#{item.tId})
foreach>
参数解释:
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
}
方法二:注解
注解说明:
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
参数解释:
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
否则会报错:
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有什么关键字
item 表示集合中每一个元素进行迭代时的别名。
index 指定一个名字,用于表示在迭代过程中每次迭代到的位置。
open 表示该语句以什么开始。
separator 表示在每次进行迭代之间以什么符号作为分隔符。
close 表示以什么结束。
在使用
如果传入的是单参数且参数类型是一个List,collection属性值为list。
如果传入的是单参数且参数类型是一个array数组,collection的属性值为array。
如果传入的参数是多个,需要把它们封装成一个Map,当然单参数也可以封装成Map。Map的key是参数名,collection属性值是传入的List或array对象在自己封装的Map中的key。
1)添加SQL映射语句
在 com.mybatis 包的 UserMapper.xml 文件中添加如下 SQL 映射语句:
2)添加数据操作接口方法
在 com.dao 包的 UserDao 接口中添加如下数据操作接口方法:
public List
3)调用数据操作接口方法
在 com.controller 包的 UserController 类中添加如下程序调用数据操作接口方法。
//使用foreach元素查询用户信息
List
listId.add(34);
listId.add(37);
List
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怎样实现主键自增呢?
select student_sequence.nextval from dual
insert into student(student_id,student_name,student_age) values(#{student_id},#{student_name},#{student_age})
或者
SELECT SEQ_ZONE.CURRVAL AS id from dual
insert into TBL_ZONE (ID, NAME ) values (SEQ_ZONE.NEXTVAL, #{name,jdbcType=VARCHAR})
4.如何使用in
在SQL语法中如果我们想使用in的话直接可以像如下一样使用:
select * from HealthCoupon where useType in ( '4' , '3' )
但是如果在MyBatis中的使用in的话,像如下去做的话,肯定会报错:
Map
select * from HealthCoupon where useType in (#{useType,jdbcType=VARCHAR})
其中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
SELECT
FROM t_user
WHERE id IN
#{id}
(二)、List
如果参数的类型是Array,则在使用时,collection属性要必须指定为 array
List
SELECT
FROM t_user
WHERE id IN
#{id}
(三)、参数有多个时
当查询的参数有多个时,有两种方式可以实现,一种是使用@Param("xxx")进行参数绑定,另一种可以通过Map来传参数。
3.1 @Param("xxx")方式
List
SELECT
FROM t_user
WHERE name=#{name,jdbcType=VARCHAR} and id IN
open="(" close=")" separator=","> #{id}
3.2 Map方式
Map
params.put("name", name);
params.put("idList", ids);
mapper.selectByIdSet(params);
select
from t_user where
name = #{name}
and ID in
#{item}