1、简介
映射文件指导着MyBatis如何进行数据库增删改查,有着非常重要的意义
2、演示 增删改
去com.atguigu.mybatis.dao下面去写增删改查方法(定义好即可)
package com.atguigu.mybatis.dao;
public interface EmployeeMapper {
//多条记录封装一个map:Map<Integer,Employee>:键是这条记录的主键,值是记录封装后的javaBean
//@MapKey:告诉mybatis封装这个map的时候使用哪个属性作为map的key
@MapKey("lastName")
public Map<String, Employee> getEmpByLastNameLikeReturnMap(String lastName);
//返回一条记录的map;key就是列名,值就是对应的值
public Map<String, Object> getEmpByIdReturnMap(Integer id);
public List<Employee> getEmpsByLastNameLike(String lastName);
public Employee getEmpByMap(Map<String, Object> map);
public Employee getEmpByIdAndLastName(@Param("id")Integer id,@Param("lastName")String lastName);
public Employee getEmpById(Integer id);
public Long addEmp(Employee employee);
public boolean updateEmp(Employee employee);
public void deleteEmpById(Integer id);
}
映射文件中,为上面定义的方法添加内容
工程路径\conf\com\atguigu\mybatis\dao EmployeeMapper.xml中写增删改
<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapper">
<insert id="addEmp" parameterType="com.atguigu.mybatis.bean.Employee"
useGeneratedKeys="true" keyProperty="id" databaseId="mysql">
insert into tbl_employee(last_name,email,gender)
values(#{lastName},#{email},#{gender})
</insert>
<!-- public void updateEmp(Employee employee); -->
<update id="updateEmp">
update tbl_employee
set last_name=#{lastName},email=#{email},gender=#{gender}
where id=#{id}
</update>
<!-- public void deleteEmpById(Integer id); -->
<delete id="deleteEmpById">
delete from tbl_employee where id=#{id}
</delete>
</mapper>
进入测试类 test03, 测试增删改
(1)mybatis允许增删改直接定义以下类型返回值
* Integer、Long、Boolean、void、void
(2)我们需要手动提交数据
* sqlSessionFactory.openSession();===》手动提交
* sqlSessionFactory.openSession(true);===》自动提交
将下面的注解部分一个一个打开,即可完成测试
package com.atguigu.mybatis.test;
public class MyBatisTest {
@Test
public void test03() throws IOException{
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
//1、获取到的SqlSession不会自动提交数据
SqlSession openSession = sqlSessionFactory.openSession();
try{
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
//测试添加
Employee employee = new Employee(null, "jerry4",null, "1");
mapper.addEmp(employee);
System.out.println(employee.getId());
//测试修改
//Employee employee = new Employee(1, "Tom", "jerry@atguigu.com", "0");
//boolean updateEmp = mapper.updateEmp(employee);
//System.out.println(updateEmp);
//测试删除
//mapper.deleteEmpById(2);
//2、手动提交数据
openSession.commit();
}finally{
openSession.close();
}
}
}
最终效果:
3、主键生成方式
3.1 mysql自增方式(自动生成主键)
若数据库支持自动生成主键的字段(比如MySQL 和SQL Server),则可以设置useGeneratedKeys=”true”,然后再把keyProperty设置到目标属性上。mysql支持自增主键,自增主键值的获取,mybatis也是利用statement.getGenreatedKeys();
useGeneratedKeys="true";使用自增主键获取主键值策略
keyProperty;指定对应的主键属性,也就是mybatis获取到主键值以后,将这个值封装给javaBean的哪个属性
<!-- public void addEmp(Employee employee); -->
<!-- parameterType:参数类型,可以省略,
获取自增主键的值:
mysql支持自增主键,自增主键值的获取,mybatis也是利用statement.getGenreatedKeys();
useGeneratedKeys="true";使用自增主键获取主键值策略
keyProperty;指定对应的主键属性,也就是mybatis获取到主键值以后,将这个值封装给javaBean的哪个属性
-->
<insert id="addEmp" parameterType="com.atguigu.mybatis.bean.Employee"
useGeneratedKeys="true" keyProperty="id" databaseId="mysql">
insert into tbl_employee(last_name,email,gender)
values(#{lastName},#{email},#{gender})
</insert>
测试类中测试效果
package com.atguigu.mybatis.test;
public class MyBatisTest {
@Test
public void test03() throws IOException{
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
//1、获取到的SqlSession不会自动提交数据
SqlSession openSession = sqlSessionFactory.openSession();
try{
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
//测试添加
Employee employee = new Employee(null, "jerry4",null, "1");
mapper.addEmp(employee);
System.out.println(employee.getId());
//2、手动提交数据
openSession.commit();
}finally{
openSession.close();
}
}
}
由于开启了自增主键,因此,就算new Employee(null, "jerry4",null, "1");,那个id值就算你写了null,也没得用,也会自增。如果没有开启自增,id值就是null
3.2 Orcal获取主键方式(非自增型数据库)
而对于不支持自增型主键的数据库(例如Oracle),Oracle使用序列来模拟自增;每次插入的数据的主键是从序列中拿到的值;重点是如何获取到这个值;
则可以使用selectKey子元素:selectKey 元素将会首先运行,id 会被设置,然后插入语句会被调用
说明:keyProperty属性的“id”,就是后面sql语句中#{id}用的id
keyProperty:查出的主键值封装给javaBean的哪个属性
order="BEFORE":当前sql在插入sql之前运行
AFTER:当前sql在插入sql之后运行
resultType:查出的数据的返回值类型
BEFORE运行顺序:
先运行selectKey查询id的sql;查出id值封装给javaBean的id属性
在运行插入的sql;就可以取出id属性对应的值
AFTER运行顺序:
先运行插入的sql(从序列中取出新值作为id);
再运行selectKey查询id的sql;
演示1:两种方式
id就是查询主键sql语句的返回值别名
进入映射文件(Before和Afer都写了,用Afer多的时候注掉Before)
<insert id="addEmp" databaseId="oracle">
<!--
keyProperty:查出的主键值封装给javaBean的哪个属性
order="BEFORE":当前sql在插入sql之前运行
AFTER:当前sql在插入sql之后运行
resultType:查出的数据的返回值类型
BEFORE运行顺序:
先运行selectKey查询id的sql;查出id值封装给javaBean的id属性
在运行插入的sql;就可以取出id属性对应的值
AFTER运行顺序:
先运行插入的sql(从序列中取出新值作为id);
再运行selectKey查询id的sql;
-->
<selectKey keyProperty="id" order="BEFORE" resultType="Integer">
<!-- 编写查询主键的sql语句 -->
<!-- BEFORE-->
select EMPLOYEES_SEQ.nextval from dual
<!-- AFTER:
select EMPLOYEES_SEQ.currval from dual -->
</selectKey>
<!-- 插入时的主键是从序列中拿到的 -->
<!-- BEFORE:-->
insert into employees(EMPLOYEE_ID,LAST_NAME,EMAIL)
values(#{id},#{lastName},#{email<!-- ,jdbcType=NULL -->})
<!-- AFTER:
insert into employees(EMPLOYEE_ID,LAST_NAME,EMAIL)
values(employees_seq.nextval,#{lastName},#{email}) -->
</insert>
测试文件中 id为null,测试前,记得取全局配置文件把 环境标签改成<environments default="dev_oracle"
代码和上例一样,
没给id(id写null),也能获取到主键224
4、MyBatis参数处理(数据库操作方法的入参)
(1)单个参数
可以接受基本类型,对象类型,集合类型的值。这种情况MyBatis可直接使用这个参数,不需要经过任何处理。可直接取值
取值方法:
#{参数名}:取出参数值
(2)多个参数
任意多个参数,都会被MyBatis重新包装成一个Map传入。Map的key是param1,param2,0,1…,值就是参数的值。
Key:param1...paramN
value:传入的参数值
取值方法:
#{}:就是从map中指定的key取值(param1...paramN)
注意:如果还是用单个参数的方式取值,比如:
方法: public Employee getEmpByIdAndLastName (Integer id,string lastName)//该方法两个参数
取值还是依然:#{id),#{1astName},此时就会报异常
异常:org. apache.ibatis.binding. BindingException: Parameter 'id' not found.Available parameters are [1, e, param1, param2]
(3)命名参数:
如果不使用命名参数,默认map,key都是param1,param2,根本不认识想表达哪个值。
因此,我们可以为参数使用@Param起一个名字,MyBatis就会将这些参数封装进map中,key就是我们自己指定的名字
比如,通过明确指定封装参数时map的key; @Param ("id")多个参数会被封装成一个map,
key:使用@Param注解指定的值
value:参数值
取值方法:
#{指定的key}:取出对应的参数值
exp(命名参数):
package com.atguigu.mybatis.dao;
public interface EmployeeMapper {
public Employee getEmpByIdAndLastName(@Param("id")Integer id,@Param("lastName")String lastName);
}
映射配置文件:
即可用id,lastName完成取值
<select id="getEmpByIdAndLastName" resultType="com.atguigu.mybatis.bean.Employee">
select * from tbl_employee where id = #{id} and last_name=#{lastName}
</select>
(4)POJO(真正常用且简单快捷)
如果多个参数正好是我们业务逻辑的数据模型(就是bean中对应的属性),我们就可以直接传入pojo
#{属性名}:取出传入的pojo的属性值
(5)传入Map,(本身就是传入Map,不如我自己传)
Map:如果多个参数不是业务模型中的数据,没有对应的pojo,为了方便,我们也可以传入map#{key}:取出map中对应的值
说明:不经常使用的数据,比如只用一次的情况,就封装进Map
包com.atguigu.mybatis.dao 的EmployeeMapper接口中
package com.atguigu.mybatis.dao;
public interface EmployeeMapper {
public Employee getEmpByMap(Map<String, Object> map);
}
映射配置文件中
getEmpByMap(Map<String,Object> map)
<!-- public Employee getEmpByMap(Map<String, Object> map); -->
<select id="getEmpByMap" resultType="com.atguigu.mybatis.bean.Employee">
select * from ${tableName} where id=${id} and last_name=#{lastName}
</select>
进入测试文件,进行测试
package com.atguigu.mybatis.test;
public class MyBatisTest {
@Test
public void test04() throws IOException{
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
//1、获取到的SqlSession不会自动提交数据
SqlSession openSession = sqlSessionFactory.openSession();
try{
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
//Employee employee = mapper.getEmpByIdAndLastName(1, "tom");
Map<String, Object> map = new HashMap<>();
map.put("id", 2);
map.put("lastName", "Tom");
map.put("tableName", "tbl_employee");
Employee employee = mapper.getEmpByMap(map);
System.out.println(employee);
/*List<Employee> like = mapper.getEmpsByLastNameLike("%e%");
for (Employee employee : like) {
System.out.println(employee);
}*/
/*Map<String, Object> map = mapper.getEmpByIdReturnMap(1);
System.out.println(map);*/
/*Map<String, Employee> map = mapper.getEmpByLastNameLikeReturnMap("%r%");
System.out.println(map);*/
}finally{
openSession.close();
}
}
}
(6)TO(Transfer Object)
如果多个参数不是业务模型中的数据,但是经常要使用,推荐来编写一个TO (Transfer object)数据传输对象
Page{
int index;
int size;}
总结:
(1)public Employee getEmp (@Param("id")Integer id,string lastName);
取值: id==>#{id/param1} lastName==>#{param2}
(2)public Employee getEmp (Integer id,@Param ("e")Employee emp);
取值: id==>#{param1) lastName===>#{param2. lastName/e.lastName)
(3)##特别注意:如果是Collection (List. Set)类型或者是数组也会特殊处理。也是把传入的list或者数组封装在map中。
key: Collection (collection) ,如果是List还可以使用这个key(即list),数组使用array
public Employee getEmpById(List<Integer> ids)
取值:取出第一个id的值: #{list [0]}
5、参数处理
5.1 #与$取值的区别
#{}:可以获取map中的值或者pojo对象属性的值
${}:可以获取map中的值或者pojo对象属性的值
select * from tbl_employee where id=${id} and last_name=#{lastName)
相当于: select * from tbl_employee where id=2 and last_name=?(占位符)
区别:
#{}:是以预编译的形式,将参数设置到sql语句中; Preparedstatement;防止sql注入(因此常用)
${}:取出的值直接拼装在sql语句中;会有安全问题;
总结:
① 大多情况下,我们去参数的值都应该去使用#{},
② 但是当使用原生jdbc,不支持占位符的地方我们就可以使用$进行取值比如分表;
比如分表、排序。。。;按照年份分表拆分
select * from $(year}_salary where xxx;
select * from tbl_employee order by ${f_name} $(order)
5.2 #{}进阶使用
#{}:更丰富的用法:规定参数的一些规则:
javaType. jdbcType, mode (存储过程) 、numericScale.resultMap, typeHandler. jdbcTypeName, expression (未来准备支持的功能) ;
Exp:jdbcType规定 演示
jdbcType通常需要在某种特定的条件下被设置:在我们数据为null的时候,有些数据库可能不能识别mybatis对null的默认处理。比如Oracle (报错) ;
说明:mybatis默认对所有null值的处理,都是映射为原生Jdbc的OTHER类型(源码jdbcTypeForNull=OTHER),Mysql认识OTHER类型,但是Oracle不认识,要手动让OTHER类型转为NULL
两种解决办法
办法一:映射文件sql语句的Email字段加入参数限制规则
去全局配置文件mybatis.xml,将environments标签的default属性切换成oracle
<environments default="dev_mysql">
然后,在测试文件中,对email字段写入null值,oracle就会报错(JdbcType OTHER无效类型异常)
Employee employee= new Employee(null,"jerry3",null,"1");
解决办法,制定参数规则。在映射文件EmployeeMapper.xml的sql语句中写上 #{email ,jdbcType=NULL },规定当email为空时,指定email的jdbcType是NULL值
<insert id="addEmp" databaseId="oracle">
insert into employees(EMPLOYEE_ID,LAST_NAME,EMAIL)
values(#{id},#{lastName},#{email ,jdbcType=NULL })
<!-- AFTER:
insert into employees(EMPLOYEE_ID,LAST_NAME,EMAIL)
values(employees_seq.nextval,#{lastName},#{email}) -->
</insert>
办法二:将全局配置文件中的jdbcTypeForNull=OTHER 改为jdbcTypeForNull=NULL
<settings>
<setting name="jdbcTypeForNull" value="NULL"/>
</settings>