框架学习一点二:Mybatis的应用场景
1.Mybatis与Hibernate的区别:
Hibernate是一个标准的ORM(对象关系映射:Object Relation Mapper)框架,SQL语句自动生成,不需要写SQL语句,因此对SQL语句进行优化、修改比较困难。
应用:适用于需求变化不多的中小型项目。
Mybatis需要程序员自己编写、修改SQL语句,优化比较方便;Mybatis是一个不完全ORM框架;也可实现输入映射、输入映射。
应用:适用于需求变化较多的项目。
企业进行技术选型:以低成本高回报作为技术选型的原则,根据项目组的技术力量进行选择。
2.SqlMapConfig.xml的配置
SqlMapConfig.xml是Mybatis的全局配置文件,配置内容包括:数据库环境、mapper定义、全局参数设置等。
使用的标签:
1.properties标签:将数据连接参数单独配置在db.properties中,只需要在SqlMapConfig.xml中加载db.properties的属性值,就不需要对数据库连接参数编码。
将数据库连接参数只配置在db.properties中的原因:方便参数进行统一管理,其它xml可以引用该db.properties。
db.properties内容:
#Oracle\u6570\u636E\u5E93\u7684\u9A71\u52A8\u7C7B
jdbc.driver=oracle.jdbc.OracleDriver
#Oracle\u6570\u636E\u5E93\u7684\u8FDE\u63A5\u8DEF\u5F84
jdbc.url=jdbc:oracle:thin:@localhost:1521:orcl
#\u767B\u5F55\u7528\u6237\u540D
jdbc.user=MY
#\u767B\u5F55\u5BC6\u7801
jdbc.password=123456
在SQLMapConfig.xml中加载属性文件
<configuration>
<!-- 加载属性配置文件(xx.properties) resource属性:只能使用/连接路径 -->
<properties resource="db.properties"></properties>
<!-- 配置数据源 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" /><!-- 驱动类 -->
<property name="url" value="${jdbc.url}" /><!-- 连接路径 -->
<property name="username" value="${jdbc.user}" /><!-- 用户名 -->
<property name="password" value="${jdbc.password}" /><!-- 密码 -->
</dataSource>
</environment>
properties标签特性:
注意Mybatis按照顺序加载属性:
在properties元素体内定义的属性首先被读取,然后读取properties元素中的resource或url加载属性,它会覆盖已读取的同名属性;最后读取parameterType传递的属性,它会覆盖已读取的同名属性。
所以,通过parameterType传递的属性具有最高优先级,resource或url加载的属性次之,最低优先级是properties元素体内定义的属性。
2.setting标签
mybatis框架运行设置一些全局配置参数,(setting全局参数 配置文档)设置全局参数会影响mybatis框架运行,谨慎设置
3.typeAliases标签
设置别名。在mapper.xml中配置好多SQL语句,也需要定义许多statement,statement需要parameterType指定输入参数类型,需要resultType指定输出结果的映射类型。若指定类型时输入类的全路径不方便开发,可以针对parameterType或resultType指定的类型定义一些别名,在mapper.xml中通过别名定义,方便开发。
Mybatis默认支持的别名:
别名 映射的类型 别名 映射的类型
_byte byte _double double
_long long _float float
_short short _boolean boolean
_int int string String
_integer int byte Byte
long Long float Float
short Short boolean Boolean
int Integer date Date
integer Integer decimal BigDecimal
double Double bigdecimal BigDecimal
自定义别名:
(1)单个别名定义
<!-- 别名定义标签:给实体类设置别名 映射配置文件中的parameterType和resultType可以使用-->
<typeAliases>
<!-- 单个类进行别名定义 type属性:实体类的类路径 alias属性:别名定义-->
<typeAlias type="com.it.model.User" alias="user"/>
<!-- package标签:批量别名定义 name属性:实体类所在的包名 自动别名定义 mybatis会自动扫描该包下的所有的类进行别名定义,别名为类名(大小写都可以)-->
<package name="com.it.bean"/>
</typeAliases>
4.mapper标签
(1)通过resource加载单个映射文件 <mapper resource=" "/>
使用相对路径的资源
(2)通过url加载单个映射文件 <mapper url=" "/>
使用完全限定路径
(3)通过mapper接口加载映射文件 <mapper class=" "/>
使用mapper接口类路径
注意:此方法要求mapper接口名称和mapper映射文件名称相同,且放在同一目录中。
(4)批量加载mapper
指定mapper接口的包名,mybatis自动扫描包下 所有mapper接口进行加载
注意:此方法要求mapper接口名称和mapper映射文件名称相同,且放在同一目录下。
(5)typeHandlers(类型处理器)
Mybatis中类型处理器用于java类型和jdbc类型转换;Mybatis提供的类型处理器满足日常需求,不需要自己定义。
3.输入映射
通过parameterType指定输入参数的类型,类型可以是简单类型,HashMap哈pojo的包装类型。
1.传递pojo包装对象
(1)需求:完成用户信息的综合查询,需要传入的查询条件可能很复杂(可能包括用户信息、其他信息)
(2)定义包装类型pojo:针对上边的需求,建议使用自定义包装类型pojo,在自定义包装类型的pojo中将复杂的查询条件包装进去
public class Order {
private int id;//订单编号
private String ordertime;//订单时间
private double total;//订单总价
private int uid;//用户编号
private User user;//当前订单信息属于哪个用户
@Override
public String toString() {
return "Order [id=" + id + ", ordertime=" + ordertime + ", total=" + total + ", uid=" + uid + /*", user="
+ user + */"]";
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getOrdertime() {
return ordertime;
}
public void setOrdertime(String ordertime) {
this.ordertime = ordertime;
}
public double getTotal() {
return total;
}
public void setTotal(double total) {
this.total = total;
}
public int getuid() {
return uid;
}
public void setuid(int uid) {
this.uid = uid;
}
}
(3)OrderMapper.xml:
<!-- 查询订单信息以及相关用户 -->
<select id="selectOrderAndUser" resultMap="orderAndUser">
select o.*,u.id userid,u.username,u.birthday,u.password from orders o, tuser u where o.userid=u.id
</select>
(4)OrderMapper.java
import java.util.List;
import com.it.bean.Order;
public interface OrderMapper {
/**
* 查询订单信息以及相关用户信息
* */
public List<Order> selectOrderAndUser();
}
(5)测试代码
public class Crud {
@Test
public void selectOrderAndUser() throws IOException{
//加载全局配置文件
Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml");
//创建会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
//打开会话
SqlSession session = factory.openSession();
//获取Mapper接口的代理方法
OrderMapper mapper= session.getMapper(OrderMapper.class);
//调用响应方法
List<Order> orders = mapper.selectOrderAndUser();
for(Order order:orders){
System.out.println(order);
}
//关闭会话
session.close();
}
}
4.输入映射
resultType:
1.resultType输出pojo对象:
使用resultType进行输出映射,只有查询出来的字段名和pojo中的属性名一致,该列才可以映射成功
若查询出来的列名和pojo中的属性名全部不一致,没有创建pojo对象
只要查询出来的列名和pojo中的属性名有一个一致,就会创建pojo对象
2.resultType输出简单类型
需求:查询出来的结果集只有一行并且只有一列,可以使用简单数据类型进行输出映射
3.resultType输出HashMap类型
当多表查询时,可以使用HashMap进行输出映射,查询的字段名即为Map集合的key值,字段值为Map集合的value值。
resultMap
1.使用方法:如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性之间做一个映射关系。
a)定义resultMap
<!-- 定义resultMap
查询出的字段名和实体类中的属性名不一致时,借助resultMap来完成字段和属性之间的映射
type:表示映射成的Java对象类型,可以使用别名
id属性:表示当前resultMap的唯一标识
-->
<resultMap type="user" id="resultMap1">
<!-- id属性用来表示主键和实体类中唯一的属性
column属性表示查询出的字段名
property属性要映射到实体类中的属性名
-->
<id column="id_" property="id"/>
<result column="loginname_" property="loginname"/>
<result column="password_" property="password"/>
<result column="realname_" property="realname"/>
<result column="sex_" property="sex"/>
<result column="birthady_" property="birthday"/>
<result column="dep_" property="dep"/>
<result column="email_" property="email"/>
<result column="enabled_" property="enabled"/>
<result column="createman_" property="createman"/>
</resultMap>
b)使用resultMap作为statement的输出映射
<!-- 使用resultMap属性 -->
<select id="login" parameterType="java.util.Map" resultMap="resultMap1">
<!-- 若参数类型为Map集合时,#{}中写的是map集合中的key值 -->
select id id_, loginname loginname_,password password_,realname realname_, sex sex_,birthday birthday_,dep dep_,email email_,enabled enabled_, createman createman_,last_login_time last_time from tuser where loginname=#{loginname} and password = #{password}
</select>
c)测试
@Test
public void login() throws IOException{
//加载全局配置文件
Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml");
//根据全局配置文件来创建回话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
//根据会话工厂来创建会话对象
SqlSession session = factory.openSession();
//获取Mapper接口的代理对象
UserMapper mapper = session.getMapper(UserMapper.class);
//创建Map集合
Map<String, String> loginCondition = new HashMap<>();
loginCondition.put("loginname", "xiaoli");
loginCondition.put("password", "123456");
//调用相应的登录方法
User user = mapper.login(loginCondition);
System.out.println(user);
//关闭事务
session.close();
}
5.动态SQL
1。什么是动态SQL:Mybatis核心对SQL语句进行灵活操作,通过表达式进行判断,对SQL进行灵活拼接,组装。
2.需求:对查询条件进行判断,如果输入参数不为空才进行查询条件拼接。
3.Mapper.xml
<!-- 使用动态SQL语句查询用户信息 -->
<select id="selectUserByDncSql" parameterType="user" resultType="user">
select * from tuser
<where>
<!-- 判断查询条件 -->
<!-- 判断是否根据用户名模糊查询
where标签会自动去掉第一个满足条件的and
-->
<if test="loginname!=null and loginname!=''">
and loginname like '%${loginname}%'
</if>
<!-- 判断是否可用查询用户 -->
<if test="enabled!=0 and enable!=null">
and enable=#{enable}
</if>
</where>
</select>
4.测试
@Test
public void selectUserByDncSql() throws IOException{
//加载全局配置文件
Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml");
//根据全局配置文件来创建回话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
//根据会话工厂来创建会话对象
SqlSession session = factory.openSession();
//获取Mapper接口的代理对象
UserMapper mapper = session.getMapper(UserMapper.class);
//若传null,为全查
//List<User> users = mapper.selectUserByDncSql(null);
User user1 = new User();
user1.setLoginname("a");
List<User> users = mapper.selectUserByDncSql(user1);
for(User user:users){
System.out.println(user);
}
//关闭事务
session.close();
}
5.sql片段
(1)将以实现的sql代码块抽取出来,组成一个SQL片段;其它的statement中就可以引用这个sql片段。
(2)定义SQL片段
<sql id="userColumns">
id, loginname,password,realname, sex,birthday,dep,email,enabled, createman,last_login_time
</sql>
(3)引用SQL片段:在mapper.xml文件的statement中引用SQL片段
<select id="selectUserById" parameterType="int" resultType="user">
<!-- include标签:引用 -->
select <include refid="userColumns"></include> from tuser where id = #{id}
</select>
6.foreach
向sql传递数组或List,mybatis使用foreach解析
(1)需求在用户查询列表中根据多个id批量删除用户信息
(2)使用数组进行批量删除和集合的方式
在输入参数类型中添加多个id
/**
* 批量删除用户信息
* 使用数组的方式
* */
public int batchDeleteUsers(int[] ids);
/**
* 批量删除用户信息
* 使用集合的方式
* */
public int batchDeleteUsers1(List<Integer> ids);
(3)修改mapper.xml
<!-- 批量删除 -->
<delete id="batchDeleteUsers">
delete from tuser
<where>
<!-- 若Mapper接口方法中的参数为数组类型,就写array -->
<if test="array!=null">
<!-- foreach标签适用于遍历参数类型为数组或集合的 collection属性:若Mapper接口方法中的参数为数组类型,固定写array
for(int id:array){}
ids={3,27,281}
delete from tuser where id in(3,27,281)
item属性:表示每遍历一个对象属性赋值给哪个属性
open属性:开始遍历时拼接的SQL字符串
separator属性:表示两个对象之间的分隔符
close属性:表示结束遍历时拼接的SQL字符串
-->
<!-- <foreach collection="array" item="id" open="id in (" separator="," close=")">
#{id}
</foreach> -->
<!-- delete from tuser where id = 3 or id = 27 or id = 281 -->
<foreach collection="array" item="id" separator=" or ">
id=#{id}
</foreach>
</if>
<!-- 说明数组为空(必须加,否则全删)说明不删除任何用户信息 -->
<if test="array==null">
1=2
</if>
</where>
</delete>
<!-- 批量删除2 通过集合-->
<delete id="batchDeleteUsers1">
delete from tuser
<where>
<if test="list!=null">
<foreach collection="list" item="id" open="id in (" separator="," close=")">
#{id}
</foreach>
</if>
<if test="list == null">
2=3
</if>
</where>
</delete>
(4)测试
/**
* 批量删除用户
* 通过数组的方式
* */
@Test
public void batchDeleteUsers() throws IOException{
//加载全局配置文件
Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml");
//根据全局配置文件来创建回话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
//根据会话工厂来创建会话对象
SqlSession session = factory.openSession();
//获取Mapper接口的代理对象
UserMapper mapper = session.getMapper(UserMapper.class);
int[] ids={4,8};
int result = mapper.batchDeleteUsers(ids);
System.out.println("已删除"+result+"条记录。");
//上传事务
session.commit();
//关闭事务
session.close();
}
/**
* 批量删除用户
* 通过集合的方式
* */
@Test
public void batchDeleteUsers1() throws IOException{
//加载全局配置文件
Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml");
//根据全局配置文件来创建回话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
//根据会话工厂来创建会话对象
SqlSession session = factory.openSession();
//获取Mapper接口的代理对象
UserMapper mapper = session.getMapper(UserMapper.class);
List<Integer> ids = new ArrayList<>();
ids.add(4);
ids.add(231);
int result = mapper.batchDeleteUsers1(ids);
System.out.println("已删除"+result+"条记录。");
//上传事务
session.commit();
//关闭事务
session.close();
}