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 users = userMapper.selectAll();
然后同样释放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区域就可

*传参问题
参数占位符:

  1. {}:会将其替换为 ?,为了防止SQL注入

  2. ${}: 拼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
替换where把if条件都框起来,这样就避免了and

<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每一项分隔用,

``` void deleteByIds(@Param("ids") int[] ids); delete from tb_brand where id in ( //或者in后的()去掉在foreach标签里写open="(" close=")"来替换掉() #{id} ); ```

多个参数: 封装为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);

posted @ 2024-01-17 16:36  launch  阅读(10)  评论(0编辑  收藏  举报