JavaWeb合集07-MyBatis

七、MyBatis

MyBatis是一款优秀的持久层(dao)框架,用于简化JDBC的开发。

MyBatis本是Apache的一个开源项目iBatis, 2010年这个项目由apache迁移到了google code,并且改名为MyBatis。2013年11月迁移到Github。

官网:https://mybatis.net.cn/

1、MyBatis入门

1.1 入门案例

使用Mybatis查询所有用户数据

实现步骤:

  1. 准备工作(创建springboot工程、数据库表user、 实体类User)

  2. 引入Mybatis的相关依赖,配置Mybatis(1。)

# application.properties文件中配置
#配置mysql驱动
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#配置主机地址和数据库
spring.datasource.url=jdbc:mysql://localhost:3306/tatabaseName
#配置数据库用户名
spring.datasource.username=root
#配置数据库密码
spring.datasource.password=1234
  1. 编写SQL语句(注解/XML),z这就是User实体类的接口
//持久层,接口;通过调用接口UserDao中的list方法来启动查询
@Component   //spring提供,将该接口交给ioc容器管理(控制反转的体现)
@Mapper     //Mybatis提供,主要被用来将SQL语句映射到接口方法上,从而简化数据库操作。
public interface UserDao {
  //@select写查询语句
@Select("select * from user")
  //定义对应的接口方法,将查询的结果放到list对象中返回
public List<User> getAllUser();
  1. 去测试类中测试编写好的接口
@SpringBootTest
class MybatisTestApplicationTests {

    //通过@Autowired注解,将ioc容器中的接口实现对象UserDao进行引入(依赖注入的体现)
    @Autowired
    private UserDao userDao;

    @Test
    void  getAlluser(){
        List list=userDao.getAllUser();
        System.out.println(list);
    }
}
1.2 配置SQL提示

由于在写SQL语句时,它是一个字符串,很容易写错,写错了也没有提示,只有运行后才报错,所以很不方便,这时就可以将SQL提示打开,在写SQL时就要提示。

选中SQL,右击,如下操作:

在这里插入图片描述

设置完毕后,SQL语句就会有高亮颜色,但是表名和对应的字段名,可能会爆红,这是因为Idea和数据库没有建立连接,不识别表信息,但是它不影响SQL的执行,只是会没有对应的提示。解决方法就是将Idea和数据库建立对应的连接,操作如下:

在这里插入图片描述

在这里插入图片描述

1.3 JDBC介绍

JDBC: (Java DataBase Connectivity),就是使用Java语言操作关系型数据库的一套API。

在这里插入图片描述

本质:

  • sun公司官方定义的一套操作所有关系型数据库的规范,即接口。
  • 各个数据库厂商去实现这套接口,提供数据库驱动jar包。
  • 我们可以使用这套接口(JDBC) 编程,真正执行的代码是驱动jar包中的实现类。

在这里插入图片描述

1.4 数据库连接池

数据库连接池是个容器,负责分配、管理数据库连接(Connection)。

它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个连接。

释放空闲时间超过最大空闲时间的连接,来避免因为没有释放连接而引起的数据库连接遗漏。

连接池优势:资源重用、提升系统响应速度、避免数据库连接遗漏。

1.4.1 数据库连接池的分类和切换

数据库连接池接口:DataSuorce;官方(sun)提供的数据库连接池接口,由第三方组织实现此接口。

功能:获取连接 Connection getConnection() throws SQLException;

连接池不需要我们自己创建,以下是常见的连接池:C3P0、DBCP、Druid(德鲁伊,阿里巴巴开源,是java语言最好用的数据库连接池之一)、Hikari(追光者,springboot默认的数据库连接池)

切换Druid数据库连接池

官方地址: https://github. com/ alibaba/ druid/ tree/ master/ druid-spring- boot-starter

只需要引入依赖就行

<!--德鲁伊 连接池对应依赖 -->
<dependency>
<groupld>com.alibaba</ groupld>
<artifactld>druid-spring- boot- starter</ artifactld>
<version>1.2.8</version>
</dependency>
#配置数据库的连接信息
spring.datasource.driver-class-namlg=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/DatabaseName
spring.datasource.username=root
spring.datasource.password=1234
1.5、Lombok

Lombok是一个实用的Java类库,能通过注解的形式自动生成构造器、getter/setter. equals、 hashcode、 toString等方法,并可以自动化生成日志变量,简化java开发、提高效率。

注解作用
@Getter/@Setter为所有的属性提供get/set方法
@ToString会给类自动生成易阅读的toString方法
@EqualsAndHashCode根据类所拥有的非静态字段自动重写equals方法和hashCode方法
@Data提供 了更综合的生成代码功能( @Getter + @Setter + @ToString + @EqualsAndHashCode)
@NoArgsConstructor为实体类生成无参的构造器方法
@AllArgsConstructor为实体类生成除了static修饰的字段之外带有各参数的构造器方法。

注意:Lombok会在编译时,自动生成对应的java代码。我们使用lombok时,还需要安装一个lombok的插件(idea自带)。

在这里插入图片描述

2、MyBatis的基础操作

通过Mybatis的注解方式实现对数据库的增删改查。

2.1 根据Id删除数据

根据id删除用户表中的数据

  1. 在User实体类的对应接口中写对应方法和SQL语句

    @Component
    @Mapper
    public interface UserDao {
      //如果想要动态的删除对应ID的用户,就要通过方法来将Id传递过来,通过 #{ } 来写传递过来的参数名
        @Delete("delete from tb_user where uid=#{uid}")
        //它会返回被影响数据的条数(0,删除失败,1删除成功)所有返回值设置为int类型
        public  int delUserById(int uid);
        }
    
  2. 在测试类中测试对应的删除方法

    @SpringBootTest
    class MybatisTestApplicationTests {
    
        @Autowired
        private UserDao userDao;
    
        @Test
        void  delUserById(){
            //调用接口的方法,将用户Id作为参数传递过去,删除用户Id为38的用户
          int delNum= userDao.delUserById(38);
            System.out.printf(delNum==1?"删除成功":"删除失败");
        }
    }
    
2.2 日志输出

由于在操作后不知道,Mybatis到底执行了那写操作,这时就可以开启日志输出。

可以在application.properties文件中,打开mybatis的日志,并指定输出到控制台。

#指定mybatis输出日志的位置,输出控制台
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.Std0utlmpl
2.2.1 预编译SQL

通过日志会发现,执行的SQL语句中,通过动态来传入要删除数据的ID语句,条件等于的是一个"?" ,这就是预编译SQL。

优势:性能提高、防止SQL注入:

①性能提高:因为MySQL有缓存的机制,如果执行相同的SQL语句,就会从缓存区中获取编译好的SQL语句,直接执行。如果没有缓存的SQL语句,就会去重新编译。如果不用预编译SQL,那么只要Id不同,就会判断它是一条新的SQL语句,就会重新去编译;如果条件值用“?”来代替(预编译SQL),尽管条件值不同也会从缓存区中拿取编译好的SQL执行。

②防止SQL注入:SQL注入是通过操作输入的数据来修改事先定义好的SQL语句,以达到执行代码对服务器进行攻击的方法。通过“?”代替的条件会将其看成条件的一个值,不会识别为语句。

通过占位符(#{})写的SQL语句就自动的是预编译SQL,有两种占位符,这是它们的区别。

在这里插入图片描述

2.2 新增用户
  1. 在UserDao接口中写新增用户的SQL及方法

    @Component
    @Mapper
    public interface UserDao {
        @Insert("insert into tb_user(email, password, nick_name, fase, admin, sex, birthday) values (#{email},#{password},#{nickName},#{fase},#{admin},#{sex},#{birthday})")
        public int addUser(User user);
        }
    
  2. 在测试类中对新增方法进行测试

    @SpringBootTest
    class MybatisTestApplicationTests {
    
        @Autowired
        private UserDao userDao;
    
        @Test
        void addUser(){
            //准备数据
            User user=new User();
            user.setEmail("123456@qq.com");
            user.setPassword("123456");
            user.setSex("男");
            user.setAdmin(1);
            user.setFase("123.jpg");·
            user.setNickName("永恒之月20");
            user.setBirthday(LocalDateTime.now());
            //调用插入数据的接口方法
            int addNum=userDao.addUser(user);
            System.out.println(addNum==1?"插入成功":"插入失败");
        }
    }
    
2.2.1 主键返回

就是在新增加完数据后,要获取到新增数据的主键(新增完数据并返回主键值)

场景:在多对多的表关系中,需要建立中间表,就需要在新增完数据后,将主键值添加到中间表中这样,这时就需要获取到主键值。

实现方法,在插入SQL注解上加上:@Options(keyProperty="id",useGeneratedKeys = true),keyProperty="id"参数表示返回的值是对象中的id属性,useGeneratedKeys表示我们需要拿到生成的主键值。

@Component
@Mapper
public interface UserDao {
    @Options(keyProperty = "uid",useGeneratedKeys = true)
    @Insert("insert into tb_user(email, password, nick_name, fase, admin, sex, birthday) values (#{email},#{password},#{nickName},#{fase},#{admin},#{sex},#{birthday})")
    public int addUser(User user);
}
@SpringBootTest
class MybatisTestApplicationTests {

    @Autowired
    private UserDao userDao;

    @Test
    void addUser(){
        //准备数据
        User user=new User();
        user.setEmail("12345@qq.com");
        user.setPassword("123456");
        user.setSex("男");
        user.setAdmin(1);
        user.setFase("123.jpg");
        user.setNickName("永恒之月20");
        user.setBirthday(LocalDateTime.now());
        //调用插入数据的接口方法
        int addNum=userDao.addUser(user);
        System.out.println(addNum==1?"插入成功":"插入失败");
        System.out.println(user.getUid());   //在加完@Options后,这里就可以拿到插入数据的主键
    }
        
    }
}
2.3 查询用户信息
2.3.1 根据ID查询用户信息

查询指定ID员工,查询男员工数量

  1. 在UserDao接口中编写查询用户的SQL及方法

    @Component
    @Mapper
    public interface UserDao {
        //查询男用户的数量
        @Select("select count(*) from tb_user where sex='男'")
        public  int  getManNum();
    
        //查询指定邮箱的员工信息
        @Select("select * from tb_user where email=#{email}")
        public User getUserById(String email);
    
    }
    
  2. 在测试类中对查询方法进行测试

    @SpringBootTest
    class MybatisTestApplicationTests {
    
        @Autowired
        private UserDao userDao;
    
        @Test
        void  getManNum(){
            System.out.println(userDao.getManNum());
        }
    
    
        @Test
        void getUserById(){
          User user=  userDao.getUserById("123@qq.com");
            System.out.println(user.toString());
    //User(uid=45, email=123@qq.com, password=1bbd886460827015e5d605ed44252251, nickName=null, fase=https://s1.ax1x.com/2023/04/15/p9S5eld.png, userStatus=null, admin=0, sex=男, birthday=2024-06-24T00:00)
    
       
    
2.3.2 数据封装

可以发现,如果数据库里面的字段与实体类里面的属性名不一致时(数据表字段用下划线分隔,实体类里面的是驼峰命名的情况),查询出来的字段值为null,解决方法如下:

方案一:通过给数据表字段取别名,让别名与实体类属性一致

 @Component
@Mapper
public interface UserDao {
@Select("select uid, email, password, nick_name as nickName, fase, admin, user_status as userStatus, sex, birthday from tb_user where email=#{email}")
    public User getUserById(String email);
}
@SpringBootTest
class MybatisTestApplicationTests {

    @Autowired
    private UserDao userDao;

    @Test
    void getUserById(){
      User user=  userDao.getUserById("123@qq.com");
        System.out.println(user.toString());
 //User(uid=45, email=123@qq.com, password=1bbd886460827015e5d605ed44252251, nickName=111, fase=https://s1.ax1x.com/2023/04/15/p9S5eld.png, userStatus=0, admin=0, sex=男, birthday=2024-06-24T00:00)

    }
}

方案二: 通过@Results, @Result注解手动映射封装

@Component
@Mapper
public interface UserDao {
    @Results({
            @Result(column = "nick_name",property = "nickName"),
            @Result(column = "user_status",property = "userStatus")
    })
    @Select("select * from tb_user where email=#{email}")
    public User getUserById(String email);
}

方案三(推荐):开启mybatis的驼峰命名自动映射开关

在配置文件application.properties 中添加配置;开启后,如果字段名与属性名符合驼峰命名规则,mybatis会自动通过驼峰命名规则映射。

mybatis.configuration.map-underscore-to-camel-case=true
2.3.3 列表条件查询

列表条件查询通常带有模糊查询,但是使用like模糊查询后面的条件中引号里面不能使用”%“号来模糊匹配,这时就要使用 concat() 函数来将百分号与模糊查询字符进行拼接。

  1. 在UserDao接口中编写查询用户的SQL及方法

    @Component
    @Mapper
    public interface UserDao {
        //使用MySQL函数concat() 对like条件里面的%号进行拼接
    @Select("select * from tb_user where email like concat('%',#{email},'%') and user_status=#{userStatus} and sex=#{sex}")
        public List<User> getLikeUser(User user);
    }
    
  2. 在测试类中对查询方法进行测试

    @SpringBootTest
    class MybatisTestApplicationTests {
    
        @Autowired
        private UserDao userDao;
    
           @Test
        void getListUser(){
            //创建要模糊查询的对象
            User user=new User();
            user.setEmail("12");
            user.setSex("男");
            user.setUserStatus(1);
            //查询出来的结果放到list集合中,通过forEach遍历出来
           List<User> list= userDao.getLikeUser(user);
           list.forEach(user1->{
               System.out.println(user1.toString());
           });
        }
    
    }
    
2.4 修改用户信息

指定用户的ID对其数据进行修改

  1. 在UserDao接口中编写修改用户的SQL及方法

    @Component
    @Mapper
    public interface UserDao {
    @Update("update  tb_user set password=#{password},nick_name=#{nickName},sex=#{sex} where email=#{email}")
        public int updateUserById(User user);
    }
    
  2. 在测试类中对修改方法进行测试

    @SpringBootTest
    class MybatisTestApplicationTests {
    
        @Autowired
        private UserDao userDao;
    
        @Test
        void  updateUserById(){
            User user=new User();
            user.setNickName("小丑");
            user.setSex("女");
            user.setPassword("654321");
            user.setEmail("1234@qq.com");
           int updateIs=userDao.updateUserById(user);
            System.out.println(updateIs==1?"修改成功":"修改失败");
        }
    
    }
    

3、XML映射文件

使用Mybatis的注解,主要是来完成一些简单的增删改查功能。如果需要实现复杂的SQL功能,建议使用XML来配置映射语句。

使用xml文件映射SQL语句后,在接口里就可以直接书写方法,不用写SQL语句。如下:

@Component
@Mapper
public interface UserDao {
  //  @Select("select * from tb_user where email like concat('%',#{email},'%') and user_status=#{userStatus} and sex=#{sex}")
    public List<User> getLikeUser(User user);
}

xml文件书写规范:

XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)。

XML映射文件的namespace属性为Mapper接口全限定名一致。

XML映射文件中sql语句的id与Mapper接口中的方法名一致,并保持返回类型一致。

在这里插入图片描述

  1. 在resource目录下创建对应的目录以及xml文件

    注意:在resource目录下创建Directory可以使用”/“来分隔,这样就像包名用”.“分隔一样,可以一次性创建多级目录。创建xml文件就直接创建文件,在后面加上xml后缀名即可。

  2. 编写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">
    
  3. 书写Mapper标签,并且标签的属性namespace要与对接的接口的全限定名保持一致。

    注:直接去找对应的接口,在接口名上右击->Copy Reference 复制即可。

    <?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接口的全限定名保持一致-->
    <mapper namespace="com.yhzyai.dao.UserDao">
    
    </mapper>
    

    在这里插入图片描述

  4. 可以直接在xml文件中的mapper标签里书写要执行的SQL语句

    <?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">
    
    <mapper namespace="com.yhzyai.dao.UserDao">
    
    <!-- id:必须与对应的Mapper接口里面的方法名保持一致 -->
    <!--    resultType:单条数据封装的数据类型,由于list集合里面存放发是user对象,这里直接拷贝User的实体类的全类名-->
    <select id="getLikeUser" resultType="com.yhzyai.pojo.User">
     select * from tb_user where email like concat('%',#{email},'%') and user_status=#{userStatus} and sex=#{sex}
    </select>
    
    </mapper>
    
  5. 通过测试方法对其进行测试

    @SpringBootTest
    class MybatisTestApplicationTests {
    
        @Autowired
        private UserDao userDao;   
    
    @Test
        void getListUser(){
            User user=new User();
            user.setEmail("12");
            user.setSex("男");
            user.setUserStatus(1);
           List<User> list= userDao.getLikeUser(user);
           list.forEach(user1->{
               System.out.println(user1.toString());
           });
        }
    }
    

4、Mybatis动态SQL

随着用户的输入或外部条件的变化而变化的SQL语句,我们称为动态SQL。

例如:在根据多个条件查询时,我只需要某几个条件,而有些条件我不需要了,这时它的数据就是null,而SQL语句的条件字段值也为null,这样是查询不不数据的,这时就需要通过动态SQL来控制某些条件不需要判断。

4.1 if-动态SQL标签

:用于判断条件是否成立。使用test属性进行条件判断,如果条件为true,则拼接SQL。

<?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">
<mapper namespace="com.yhzyai.dao.UserDao">

<select id="getLikeUser" resultType="com.yhzyai.pojo.User">
    <!--使用if前-->
 <!-- select * from tb_user where email like concat('%',#{email},'%') and user_status=#{userStatus} and sex=#{sex}-->
 
  <!--  使用if后-->
select * from tb_user where
    <!--如果email不为空,那么就执行对应条件-->
 <if test="email !=null">
 email like concat('%',#{email},'%')
 </if>
 <if test="userStatus !=null">
 and user_status=#{userStatus}
 </if>
 <if test="sex !=null">
 and sex=#{sex}
 </if>
</select>

</mapper>

//测试
@SpringBootTest
class MybatisTestApplicationTests {

@Autowired
private UserDao userDao;
 @Test
    void getListUser(){
        User user=new User();
        user.setEmail("12");
        //将性别设置为空(不限制性别)
        user.setSex(null);
        user.setUserStatus(1);
       List<User> list= userDao.getLikeUser(user);
       list.forEach(user1->{
           System.out.println(user1.toString());
       });
    }
}
4.2 where-动态SQL标签

:用来替换SQL语句中的where,如果不用where标签时,上一个例子的SQL语句,当条件里的email为空时,if标签里的条件就不会执行,那么组合起来的SQL语句条件前面就会多一个and ,导致SQL语句出错。如: select * from tb_user where and user_status=? and sex=?

  1. 在对应Mapping接口中书写对应方法
@Component
@Mapper
public interface UserDao {
   public List<User> getLikeUser(User user);
}

添加where标签后,执行的SQL:select * from tb_user WHERE user_status=? and sex=?

<?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">
<mapper namespace="com.yhzyai.dao.UserDao">

<select id="getLikeUser" resultType="com.yhzyai.pojo.User">

 select * from tb_user
<!--添加where标签,包裹if标签-->
 <where>
 <if test="email !=null">
 email like concat('%',#{email},'%')
 </if>
 <if test="userStatus !=null">
 and user_status=#{userStatus}
 </if>
 <if test="sex !=null">
 and sex=#{sex}
 </if>
 </where>
</select>

</mapper>
//测试
@SpringBootTest
class MybatisTestApplicationTests {

@Autowired
private UserDao userDao;
 @Test
    void getListUser(){
        User user=new User();
        //将email设置为空
        user.setEmail(null);
        user.setSex("男");
        user.setUserStatus(1);
       List<User> list= userDao.getLikeUser(user);
       list.forEach(user1->{
           System.out.println(user1.toString());
       });
    }
}

4.3 案例-动态修改数据

如果使用注解的方法来执行SQL修改语句时,不需保证,所有数据都必须修改,要不然没有修改的字段,就会被修改为 null,这时就需要用到xml文件的方式进行动态的修改数据。

set标签:动态地在行首插入SET关键字,并会删掉额外的逗号。( 用在update语句中)

  1. 在Mapper接口中书写对应修改方法
@Component
@Mapper
public interface UserDao {
 public int updateUserById(User user);
}

2.在xml映射文件中书写修改的SQL语句

<?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">
<mapper namespace="com.yhzyai.dao.UserDao">
 <update id="updateUserById">
  update tb_user
  <set>
   <if test="nickName!=null">
   nick_name=#{nickName},
   </if>
   <if test="fase!=null">
   fase=#{fase},admin=#{admin},
   </if>

    <if test="password!=null">
     password=#{password},
    </if>

   <if test="userStatus!=null">
  user_status=#{userStatus},sex=#{sex},
   </if>
   <if test="birthday!=null">
  birthday=#{birthday}
   </if>
  </set>
  where email=#{email}
 </update>

</mapper>

3.对方法进行测试

  
@Test
    void  updateUserById(){
        //准备数据
        User user=new User();
        user.setEmail("12345@qq.com");
        user.setPassword("9999999");
//        user.setSex("男");
//        user.setAdmin(1);
//        user.setFase("123.jpg");
//        user.setNickName("永恒之2000");
//        user.setBirthday(LocalDateTime.now());
       int updateIs=userDao.updateUserById(user);
        System.out.println(updateIs==1?"修改成功":"修改失败");

    }
  //执行SQL:update tb_user SET password=? where email=?
4.4 foreach 动态SQL标签

批量执行SQL,如批量删除数据

  1. 在Mapper接口中添加对应的批量删除方法

    @Component
    @Mapper
    public interface UserDao {
     //批量删除数据方法,接收的参数是list集合装起来的要删除数据的id
        public int deleteByIds(List<Integer> ids);
    }
    
  2. 在xml文件中编写对应的SQL

    <?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">
    <mapper namespace="com.yhzyai.dao.UserDao">
    
     <delete id="deleteByIds">
    <!-- 编写SQL语句,删除id为48,51,52的用户:delete from tb_user where uid in(48,51,52)-->
    <!--   foreach 标签有5个参数:-->
    <!--    collection:要遍历的集合,直接写传过来的集合名-->
    <!--   item 遍历后的变量名,随便写个变量-->
    <!--   separator:每个遍历出来后之间的分隔符-->
    <!--  open:遍历执行前要拼接的SQL-->
    <!--   close:结束遍历后要拼接的SQL-->
    
    delete from tb_user where uid in <foreach collection="ids" item="uid" separator="," open="(" close=")" >
              #{uid}
     </foreach>
    
     </delete>
     </mapper>
    
  3. 编写测试

    @SpringBootTest
    class MybatisTestApplicationTests {
    
        @Autowired
        private UserDao userDao;
    
        @Test
        void  deleteByIds(){
            List list=new ArrayList();
            list.add(48);
            list.add(51);
            list.add(52);
          int delNum= userDao.deleteByIds(list);
            System.out.println(delNum==3?"删除成功":"删除失败");
        }
     }
    
4.5 sql和 include 标签

由于mapper配置文件中的SQL有很多重复的sql语句,导致代码比较臃肿,不易复用,这时就可以使用sql标签来将重复的sql语句进行封装起来,再使用include来进行复用。

:定义可重用的SQL片段,id属性作为标识。
:通过属性refid,指定包含的sql片段。

  1. 书写一个mapper接口的方法

    @Component
    @Mapper
    public interface UserDao {
    
      public List<User> getUserBySex(String sex);
      
      }
    
  2. 编写mapper映射,通过sql标签和include标签来按用户性别条件进行查询

    <?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">
    <mapper namespace="com.yhzyai.dao.UserDao">
    
        <!--将这种比较通用的SQL语句进行提取出来,通过sql标签-->
     <sql id="getuser">
       select uid, email, password, nick_name, fase, admin, user_status, sex, birthday from tb_user
     </sql>
    
        
     <select id="getUserBySex" resultType="com.yhzyai.pojo.User">
     <!--   select uid, email, password, nick_name, fase, admin, user_status, sex, birthday from tb_user where sex=#{sex} -->
      <!--使用include标签中的refid属性来引用对应id的sql标签中的sql语句-->
       <include refid="getuser"/>  where sex=#{sex}
     </select>
    
    </mapper>
    
  3. 测试

    @SpringBootTest
    class MybatisTestApplicationTests {
    
        @Autowired
        private UserDao userDao;
    
            @Test
            void getUserBySex(){
               List list=userDao.getUserBySex("男");
                System.out.println(list.toString());
            }
     }
    
4.6 通过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">
<mapper namespace="com.yhzyai.dao.UserDao">

<!--    trim能够自动删掉最后的,-->
<!--     prefix="("	最前面的符号为(-->
<!--     suffix=")"	结尾符号为)-->
<!--    suffixOverrides=","	不保留最后的逗号-->
    <insert id="addUser">
        insert into tb_user
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="email != null ">
                email,
            </if>
            <if test="password != null ">
                password,
            </if>
            <if test="nickName != null ">
                `nick_name`,
            </if>
            <if test="fase != null ">
                fase,
            </if>
            <if test="admin != null ">
                admin,
            </if>
            <if test="userStatus != null ">
                `user_status`,
            </if>
            <if test="sex != null ">
                sex,
            </if>
            <if test="birthday != null ">
                birthday
            </if>

        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="email != null ">
                #{email},
            </if>
            <if test="password != null ">
                #{password},
            </if>
            <if test="nickName != null ">
                #{nickName},
            </if>
            <if test="fase != null ">
                #{fase},
            </if>
            <if test="admin != null ">
                #{admin},
            </if>
            <if test="userStatus != null ">
                #{userStatus},
            </if>
            <if test="sex != null ">
                #{sex},
            </if>
            <if test="birthday != null ">
                #{birthday}
            </if>
        </trim>
    </insert>
</mapper>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/892779.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

人工智能学习框架的探索与应用

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

Spark:DataFrame介绍及使用

1. DataFrame详解 DataFrame是基于RDD进行封装的结构化数据类型&#xff0c;增加了schema元数据&#xff0c;最终DataFrame类型在计算时&#xff0c;还是转为rdd计算。DataFrame的结构化数据有Row&#xff08;行数据&#xff09;和schema元数据构成。 Row 类型 表示一行数据 …

中文情感分析课程设计

中文情感分析 中文情感分析的实质是文本分类问题&#xff0c;本项目分别采用CNN和BI-LSTM两种模型解决文本分类任务&#xff0c;并用于情感分析&#xff0c;达到不错的效果。 两种模型在小数据集上训练&#xff0c;在验证集的准确率、号回率及F1因子均接近90% 项目设计的目标…

短链接能有多短?颠覆你的认知

在我们平时的网络活动中&#xff0c;经常会遇到需要将长链接缩短的情况。有细心的小伙伴会发现&#xff0c;平时收到的短信里面都会携带一个很短的链接&#xff0c;这就是将长链接缩短之后的效果。 缩短链接的主要目的有两个&#xff1a;一是使链接更加简洁美观&#xff1b;二…

基于SSM的网上拍卖平台

文未可获取一份本项目的java源码和数据库参考。 1. 选题背景 网络在人们的日常生活所占的比重越来越重&#xff0c;人们对网络信息的依赖性也越来越高。为用户提供良好的网络服务&#xff0c;可以给用户带来便捷的同时&#xff0c;也为网络服务开发商带来了客观的收益。当前&…

4-20mA采集卡 USB温度采集卡 USB热电偶采集 USB5601多功能采集卡

阿尔泰科技 型号&#xff1a;USB5601 概述&#xff1a; 产品外形图&#xff1a; 外形尺寸图&#xff1a; 主要指标&#xff1a; 8 路差分模拟量采集、8 路隔离数字量输入和 8 路隔离数字量输出 要了解更多技术和产品知识关注我吧&#xff01;

最大公共子序列c++

最大公共子序列c 概念基本的概念 递归算法代码优化map基础优化代码 概念 基本的概念 子序列&#xff1a; 由原序列中若干个元素组成&#xff0c;元素可以不连续&#xff0c;但和原序列的顺序一致。最长公共子序列&#xff1a; 一个序列即是甲序列的子序列&#xff0c;也是乙序…

DNDC模型下载与安装;土壤碳储量;点尺度和区域尺度模拟;气象数据、土地数据、土壤数据处理、农田减排潜力分析、温室气体排放分析等

实现美丽中国建设目标&#xff0c;“双碳”行动将会发挥非常重要的作用。碳循环的精确模拟是实现“双碳”行动的关键。DNDC&#xff08;Denitrification-Decomposition&#xff0c;反硝化-分解模型&#xff09;是目前国际上最为成功的模拟生物地球化学循环的模型之一&#xff0…

spark:Structured Streaming介绍

文章目录 1. Structured Streaming介绍1.1 实时计算和离线计算1.1.1 实时计算1.1.2 离线计算 1.2 有界和无界数据 2. 简单使用3. 编程模型4. 数据处理流程4.1 读取数据Source4.1.1 文件数据处理 4.2 计算操作 Operation4.3 数据输出 Sink4.3.1 输出模式4.3.2 指定输出位置4.3.3…

Html/Vue浏览器下载并重命名文件

Html/Vue浏览器下载并重命名文件 row是上方图片的数据对象 download(row) {const link document.createElement(a);link.style.display none;// 设置下载地址link.setAttribute(href, row.url);// 设置文件名(这里可以重新设置名字&#xff0c;下载之后的文件就是你重新命名…

【数据结构与算法】链表(上)

记录自己所学&#xff0c;无详细讲解 无头单链表实现 1.项目目录文件 2.头文件 Slist.h #include <stdio.h> #include <assert.h> #include <stdlib.h> struct Slist {int data;struct Slist* next; }; typedef struct Slist Slist; //初始化 void SlistI…

死锁和活锁和线程饥饿

死锁 死锁是指两个或两个以上的线程在执行过程中&#xff0c;因争夺资源而造成的一种相互等待的现象&#xff0c;若无外力作用&#xff0c;它们都将无法推进下去。 原因&#xff1a;两个或两个以上的线程共同访问两个或多个相同的资源&#xff08;如对象锁&#xff09;&#…

Unity使用TriangleNet参考

TriangleNet下载如下&#xff1a; TriangleNet 效果如下&#xff1a; 代码参考如下&#xff1a; using System.Collections.Generic; using UnityEngine; using TriangleNet.Geometry;public class TestTriangleNet : MonoBehaviour {[SerializeField]Material material;voi…

耳夹式耳机哪个品牌音质好?五大优质音质的耳夹式耳机!

随着健康理念的传播&#xff0c;运动健身成为大众追求高品质生活的重要部分。传统耳机在运动场景下有局限性&#xff0c;稳定性差、清洁不便&#xff0c;影响运动体验。这时&#xff0c;耳夹式耳机出现&#xff0c;以独特设计和传音方式重塑运动音乐享受&#xff0c;无需入耳&a…

游戏推荐业务中基于 sentinel 的动态限流实践

作者&#xff1a;来自 vivo 互联网服务器团队- Gao Meng 本文介绍了一种基于 sentinel 进行二次开发的动态限流解决方案&#xff0c;包括什么是动态限流、为什么需要引入动态限流、以及动态限流的实现原理。 一、背景 1.1 当前的限流方案 随着互联网的发展及业务的增长&…

Flythings学习(四)串口通信

文章目录 1 串口编程基本步骤1.1 打开串口1.2 配置串口 1.3 读串口1.4 发送串口1.5 关闭串口 2 综合使用3 如何在软件上保证串口稳定通信4 flythings中的串口通讯5 协议接收部分使用和修改方法6 通讯协议数据怎么和UI控件对接 1 串口编程基本步骤 串口通信有5个步骤 1.打开串口…

Telegram——Bot 机器人/小程序入门指南

一、Bot 介绍 在 TG 中,机器人可以用于接收和发送消息、管理群组(在有权限的情况下可以封禁用户、删除消息、置顶消息等)、通过API进行编程操作、使用 Inline 查询功能在不同的聊天室中提供查询服务、创建自定义键盘按钮、发出账单并收款、接入小程序游戏等。 然而,Bot 默…

单片机中断概念以及示例

中断允许控制寄存器 CPU对中断系统所有中断以及某个中断源的开放和屏蔽是由中断允许寄存器IE控制的。 EX0(IE.0)&#xff0c;外部中断0允许位&#xff1b;EX01&#xff0c;打开外部中断0中断&#xff1b;EX00关闭外部中断0中断。 ET0(IE.1)&#xff0c;定时/计数器T0中断允许…

沪尚茗居装修秘籍:嵌入式蒸烤箱,让厨房生活更精彩

在装修厨房时&#xff0c;选择一款合适的嵌入式蒸烤箱不仅能提升烹饪效率&#xff0c;还能为厨房增添一份现代感。沪尚茗居深知用户对厨房电器的需求&#xff0c;从实际出发&#xff0c;为用户推荐选购嵌入式蒸烤箱的实用技巧&#xff0c;让厨房生活更加美好。    首先&…

Real-World Image Variation by Aligning Diffusion Inversion Chain

https://proceedings.neurips.cc/paper_files/paper/2023/file/61960fdfda4d4e95fa1c1f6e64bfe8bc-Paper-Conference.pdfhttps://rival-diff.github.io/ 问题引入 针对的是image varation generation这个任务&#xff0c;tuning free的&#xff1b; methods C C C表示condit…