mybatis
持久层框架,用于简化jdbc
查询
新增更新删除
根据主键ID查询条件查询
根据主键ID删除根据主键ID批量删除
下面的先不详细说了,先说针对于springboot中的mybatis
引入三个依赖mybatis、Lombok、mysql驱动包
application.properties中配置数据库连接四要素
动态sql删除
@Mapper
public interface EmpMapper (
//根ID删除数据
@Delete("delete from emp where id = #{id}")
public void delete(Integer id);
//一般这个返回值是不需要的,所以一般是void如果是int会返回删除的数据条数
}
在application.properties中配置mybatis日志信息
日志对应的是log所以直接mybatislog选择impl提示的
选择stdoutimpl意味着要往控制台输出日志
预编译sql可以防止sql注入
关于登录页面的sql注入
select count() from emp where username'zhangwuji'and password =1111;
select count() from emp where username = 'wuieuwiueiwuiew' and password = '' or 'l' = '1';
?代表占位符,一个参数对应一个?就可以防止注入
mybatis中占位符有#和$
执行SQL时,会将#{}替换为?,生成预编译SQL,会自
动设置参数值。
使用时机:参数传递,都使用#{}
然而
${}拼接SQL。直接将参数拼接在SQL语句中,存在SQL注
入问题。
使用时机:如果对表名、列表进行动态设置时使用
sql新增
在添加多个参数的时候可以使用对象将多个参数直接打包
关于动态参数之间用#{对象emp的属性名字}
记得是驼峰命名法
//新增员工
@Insert("insert into emp(username, name, gender, imade, job, entrydate, dept_id, create_time, undate time)"+
"values (#{username},#{name},#{gender}, #{image},#{job},#{entrydate}, #deptId),fcreateTime), #(updateTime})")
public void insert (Emp emp);
新增主键返回
就是插入的新数据,你如果对这个对象想getid拿不到主键值
直接在@insert上方写
@Options(keyProperty = "id", useGeneratedKeys = true)
主键会封装到emp.id属性当中
sql更新
分为两步,第一步首先编辑对数据的一个回显展示,然后是修改
这种情况因为所有属性用户名都会发生变化,所以一般是根据主键id进行变化的
这个编辑,展示出页面的回显实际就是按照id查信息
实体类属性名和数据库表查询返回的字段名一致,mybatis会自动封装
如果实体类属性名和数据库表查询返回的字段名不一致,不能自动封装。sql语句不能生效则
方案一:起别名
@Select("select id, username,password,name, gender,image,job,entrydate,"+"dept_id deptId, create_time createTime, update_time updateTime from emp where id = #{id}")
public Emp getById(Integer id);
方案二:通过@Result,@Result注解手动映射封装(非常臃肿不被推荐)
@Results({
@Result(column = "dept_id", property = "deptId"),
@Result(column = "create_time",property = "createTime"),
@Result(column = "update_time",property = "updateTime")
})
@Select("select * from emp where id = #{id}")
public Emp getById(Integer id);
方案三:开启mybatis的驱峰命名自动映射开关a_column --> aCloumn
application.properties
camel = true
在进行模糊查询的时候like '%${}%'这样可以用以拼接字符串
为防止sql注入可以使用concat拼接字符串
where name like concat('%','张','%')gender = #{gender}
where name like concat('%',?,'%')and gender = #{gender}
where name like concat('%',#{name},'%')and gender = #{gender}
spring boot2.X版本的时候mapper映射的sql属性名只需要和参数名一致即可
spring boot1.X版本/单独使用mybatis则需要注解@Param("")来单独指定参数名字
xml配置文件来sql映射
规范:1.同包同名2.namespace对应mapper命位置3.sql语句的id等于方法名,返回类型一致
resultType:单条记录所封装的类型
比如这个empmapper之间找到这个emp的类文件,右键copy reference就是resultType
创建xml的时候就file即可记得copy配置xml的官方约束
配置文件要与mapper映射文件同包同名,xml放在resource资源文件下
关于配置下xml
xml的namespace要与mapper接口名一致com.hm.mapper.empmapper
使用mybatisX插件找sql定位更便捷
<mapper namespace="comitheima.mapper.EmpMapper">
<select id="list" resultType="com.itheima.pojo.Emp">
select * from emp where name like concat('%',#name),'%') and gender = #{gender} and entrydate between #{begin} and #{end} order by update_time desc
</select>
</mapper>
【1】关于xml配置文件中的动态sql的if标签判断和include看楼下
关于批量删除的sql用到了集合的运用使用foreach遍历看末尾
关于sql和include标签两者的配套使用
如果在xml映射文件中存在大量的重复的sql片段,出现问题修改的时候耦合度就过高,非常不利
sql标签就是框起来sql片段的并且定义一个唯一标识id
include负责在原来抽取的这个位置。将sql片段引用进来。refid对应指定sql的id
以下大概是单独使用mybatis或者spring老版本不多说了
查询user表中所有数据
1.创建user表,添加数据
2.创建模块,导入坐标
3.编写MyBatis 核心配置文件-- >替换连接信息解决硬编码问题
4.编写SQL映射文件--> 统一管理sql语句,解决硬编码问题
5.编码
1.定义POJ0类
2.加载核心配置文件,获取 SqlSessionFactory对象
3.获取 SqlSession 对象,执行 SQL 语句
4.释放资源
注入依赖
<dependencies>
<!--mybatis 依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
</dependencies>
<!--mysql 驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<!--junit单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
--·添加s1f4i日志api.--
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.20</version>
</dependency>
<-- 添加logback-classic依赖·-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<--添加logback-core依赖·-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
构建xml配置文件,官方名字mybatis-config.xml核心配置文件
<confiquration>
<typeAliases>
<package name=com.itheima.pojo"/>
// 相当于把pojo文件夹下的所有类起了一个别名,这个类名呢也不用区分大小写。
// 也不用带package包的名称/可以直接在usermapper配置文件下的resulttype直接写user就可以了
// 这叫包扫描,xml约束,这几句一定要写在配置顶部
</typeAliases>
<environments default="development"><environment id="development">
<transactionManager type="JDBC"/><dataSource type="POOLED">
<!--数据库连接信息-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysq:///mybatis?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers> //指定sql映射文件的路径 这里注意。直接去user那个xml右键复制文件路径path from source root
</configuration>
sql映射文件,usermapper.xml
<?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">
<-- namespace命名空间 -->
<mapper namespace="test">
<select id="selectAll” resultType="com.heima.pojo.user">
select * from tb_user;
</select>
</mapper>
pojo下的核心文件
public class MyBatisDemo {
public static void main(Stringl] args) throws IOException {
//1。 加载mybatis的核心配置文件,获取 SqLSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource); //mybatis提供的资源加载的类,类下面有方法,getresourcestream将字符串传进来,返回字节输入流
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream) build方法把流传进来
//2. 获取SqLSession对象,用它来执行
sqLSqlSession sqlSession = sqlSessionFactory.openSession();
//3.执行sql
//返回一个list集合,只需要传进去sql语句的唯一标识,usermapper语句select的唯一id:selectAll 需要加上名称空间namespace来区分是哪个包
List<user> users= sqlSession.selectList(test.selectAll);
4.释放资源
sqlSession.close();
}
}
关于以上的代理开发配置。只需要删除sqlsession代码语句第三句
直接UserMapper usermapper = sqlSession.getMapper(UserMapper.class)
直接获取这个接口的代理对象然后直接
List
然后同样释放session
,同样之前核心配置文件里的
映射文件就是xml配置文件。不能和java文件混一文件夹,要放在resouce。在资源文件夹下建一个和mapper一样的文件夹。java下开始用/分隔不用.
那么space起名com.heima.mapper.Usermapper
xml映射文件下有个select语句id为selectAll对应同名接口文件的一个selectAll方法,返回值便是user集合
xml顶层结构顺序
MyBatis 核心配置文件的顶层结构如下
configuration(配置)
properties (属性)
settings (设置)
typeAliases (类型别名)
typeHandlers(类型处理器)
objectFactory (对象工厂)
plugins(插件)
environments (环境配置)
environment(环境变量)
transactonManager(事务管理器)
datasource(数据源)
databaseldProvider(数据库厂商标识)
mappers(映射器)
安装idea的mybatisx插件可以避免statement的id所对应的方法名写错的问题
红头绳鸟是映射文件。蓝色对应接口。点鸟图标直接跳转
在接口里写方法,点击alt+enter直接创建对应的statement语句sql
一般管usermapperxml文件下的sql语句标签叫statement
MyBatis完成操作需要几步?三步: 编写接口方法-> 编写SQL--> 执行方法
关于数据库表和实体类属性名不一样问题解决
1.起别名不建议因为sql语句太多了看下
表不一样的列名起别名等于实体类的属性名
->
2.引用sql片段
缺点:不灵活
所以可以直接引用sql片段直接在映射文件的上方写sql片段
id, brand_name as brandName, company_name as companyName, ordered, description, status
然后语句引用
3.用resultmap
语句上面定义id随便起不一样就行。type类型对应需要映射的文件类。关键是下面的sql语句的resultType不要了直接改成resultMap=那个对应的resultmap的id就ok了
<resultMap id="brandResultMap" type="brand">
<result column="brand_name" property="brandName" />
<result column="company_name" property="companyName" />
</resultMap>
<select id="selectAll" resultMap="brandResultMap">
select
*
from tb_brand;
</select>
关于查询详情
Brand selectById(int id);
-关于sql语句的问题
*sql语句中的参数类型属性可写可不写
*特殊字符处理:
1.转义字符:比如<可以用<替换
2。CDATA区:写进CD区域就可
*传参问题
参数占位符:
-
{}:会将其替换为 ?,为了防止SQL注入
- ${}: 拼sql。会存在SQL注入问题。动态的拼表名列名的时候可以使用
所以为了防止sql注入一般传参都用#{}来传参
条件查询
*参数接收
1。散装参数: 如果方法中有多个参数,需要使用@Param("SOL参数占位符名称")
2。对象参数
3。 map集合参数
SQL语句设置多个参数有几种方式?
1散装参数:需要使用@Param(“SQL中的参数占位符名称”)
2实体类封装参数
只需要保证sQL中的参数名和实体类属性名对应上,即可设置成功
3map集合
只需要保证sQL中的参数名和map集合的键的名称对应上,即可设置成功
先说sql语句
<select id="selectByCondition" resultMap="brandResultMap">
select *
from tb_brand
where status = #{status]
and company_name like #{companyName}
and brand_name like # brandName]</select>
再说mapper
List<Brand> selectByCondition(@Param("status")int status, @Param("companyName") StringcompanyName,@Param(brandName") String brandName);
List<Brand> selectByCondition(Brand brand);
List<Brand> selectByCondition(Map map);
实体类使用set设置参数
map使用push设置参数
Map map = new HashMap();
map.put("status", status);
map.put("companyName",companyName);
map.put("brandName",status);
List<Brand> setectByCondition(@Param("status") int status, @Param("companyName") String companyName,@Param("brandName") String branName){}
用户输入条件时,是否所有条件都会填写?
SQL语句会随着用户的输入或外部条件的变化而变化,我们称为 动态SQL
【1】查询
多条件-动态条件查询
关于动态sql
if
choose (when, otherwise)
where(trim,set)
foreach
if条件判断,test逻辑表达式
问题:
恒等式1=1
<select id="selectByCondition" resultMap="brandResultMap">
select *
from tb_brand
//where 1=1
<where>
<if test="status != null">
and status = #{status}
</if>
<if test="companyName != null and companyName != '' “>
and company_name like #{companyName}
</if>
<if test="brandName != null and brandName != '' “>
and brand_name like #{brandName}
</if>
</where>
</select>
单条件-动态条件查询
choose(when,otherwise)
switch(case,defult)
<select id="selectByConditionSingle" resultMap="brandResultMap">
select *
from tb_brand
<where>
<choose>
<when test="status != null">
status = #{status]
</when>
<when test="companyName != null and companyName != '' ">
company_name like #{companyName}
</when>
<when test="brandName != null and brandName != ">
brand_name like #{brandName}
</when>
<otherwise>
1=1
</otherwise>
</choose>
</where>
</select>
添加
因为没有自动提交autocommit要执行事务提交
<insert id="add">
insert into tb_brand (brand_name, company_name, ordered, description, status)
values (# brandName},#{companyName},#ordered),#{description},#{status})
</insert>
//3。获取Mapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//4. 执行方法
brandMapper.add(brand);
//提交事务
sqlSession.commit();
//1.获取SgLSessionFactory
String resource = "mybatis-config.xm":InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2。获取SgLSession对象
//SqlSession sqlSession = sqlSessionFactory.openSession();
SqlSession sqlSession = sqlSessionFactory.openSession( autoCommit: true);
--关于执行事务的问题
MyBatis事务:
openSession():默认开启事务,进行增删改操作后需要使用 slSession.commit(); 手动提交事务
openSession(true): 可以设置为自动提交事务(关闭事务)
--返回添加数据的主键
执行添加数据成功后获取不到此条id
useGeneratedKeys="true" keyProperty="id"
<insert id="addOrder" useGeneratedKeys="true" keyProperty="id">
insert into tb order (payment, payment type, status)
values(#payment;,#paymentType),#status);
</insert>
<insert id="addOrderltem">
insert into tb order item (goods name, goods price, count,order id)
values(#{goodsNam,#goodsPrice},#{count;,#orderld;);
</insert>
修改
全部字段
动态字段
<update id="update">
update tb_brandset
brand_name = #{brandName}
company_name = #{companyName}
ordered = #{ordered},
description = #{description}
status = #istatus]
where id = #{id};
</update>
set标签就是替换set的可以避免if标签里面结尾每一个多余的逗号,
<update id="update">
update tb_brand
<set>
<if test="brandName != null and brandName != ii">
brand_name = #{brandName}</if>
<if test="companyName != null and companyName != ">
company_name = #{companyName}
</if>
<if test="ordered != null">
ordered = #{ordered}
</if>
<if test="description != null and description != ">
description = #{description}
</if>
<if test="status != null">
status = #istatus]
</if>
</set>
where id = #{id}:
</update>
删除
--批量删除
mybatis会将数组参数,封装为一个Map集合
- 默认: array = 数组 //不用param直接ids改成array
- 使用@Param注解改变map集合的默认key的名称
遍历参数数组,需要@parameter来裱起来separate每一项分隔用,
多个参数: 封装为Map集合,可以使用@Param注解,替换Map集合中默认的arg键名
map.put("arg0",参数值1)
map.put("param1",参数值1)
map.put("param2"参数值2)
map.put("agr1",参数值2)
mybatis底层是用map封装参数的
悬念:关于collection/List/Array
注解完成简单功能
配置文件完成复杂功能
注解完成sql
@SeLect("select * from tb_user where id = #{id}")
User selectById(int id);