首页 > 数据库 >MyBatis入门及sql语句实战

MyBatis入门及sql语句实战

时间:2024-10-18 19:43:32浏览次数:1  
标签:语句 name 映射 where 查询 sql MyBatis tb id

目录

概述

半自动的ORM持久层框架

具有较高的SQL灵活性,支持高级映射,动态SQL,延时加载和缓存等特性数据库无关性较低

环境的配置

在回顾JDBC时,我们已经创建有Maven工程,而且在pom.xml中也已经导入 mysql 依赖包,这里就直接在原有工程上搭建MyBatis环境,以及使用MyBatis来实现JDBC查询user的操作流程。

MyBatis操作步骤总结

通过上述操作,我们可以总结出 MyBatis 的操作步骤如下:

  1. 创建 UserMapper.java 映射器接口
  2. 创建 UserMapper.xml 映射文件
  3. 在 mybatis-config.xml 环境配置文件中添加 UserMapper.xml 映射文件路径
  4. 在 MyBatisDemo中编写MyBatis测试代码
    • 加载 mybatis-config.xml MyBatis环境配置文件
    • 创建 SqlSessionFactory 工厂对象
    • 通过 SqlSessionFactory 工厂创建 SqlSession 对象
    • 通过 SqlSession 创建 UserMapper接口对象
    • 调用 UserMapper 接口方法执行查询操作
    • 调用SqlSession.commit()提交事务(查询不需要)
    • 关闭 SqlSession 会话

MyBatis环境搭建

首先,在 Maven 项目的 pom.xml 中添加 MyBatis 的依赖 jar 包

<!--导入 mybatis 依赖包-->
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>3.2.8</version>
</dependency>          

然后,在Maven工程的 resources 目录下创建 MyBatis 环境配置文件 mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
    <settings>
         <!--是否开启自动加载驼峰命名规则映射映射文件 -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    <!-- 数据库配置 -->
    <environments default="development">
        <environment id="development">
            <!-- 事务管理器,JDBC类型的事务管理器 -->
            <transactionManager type="JDBC" />
            <!-- 数据源,池类型的数据源 -->
            <dataSource type="POOLED">
                <!--设置数据库驱动 -->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <!--设置数据库url地址-->
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?                  useUnicode=true&amp;characterEncoding=UTF8&amp;useSSL=false&amp;allowPublicKeyRetrieval=true&amp;serverTimezone=GMT%2B8&amp;allowMultiQueries=true"/>
                <!--设置数据库用户名-->
                <property name="username" value="root"/>
                <!--设置数据库密码-->
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <!-- 配置映射文件路径 -->
    <mappers>
        <!--配置xml映射文件路径-->
        <mapper resource="mappers/UserMapper.xml" />
        <mapper resource="mappers/OrderMapper.xml" />
        <mapper resource="mappers/GameMapper.xml" />
        <!--配置注解接口路径-->
<!--        <mapper class="mapper.UserMapper" />-->
<!--        <mapper class="mapper.GameMapper" />-->
    </mappers>

</configuration>

最后,在Maven工程的main/java下创建MyBatisDemo.java文件,用于测试MyBatis环境是否搭建OK

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * @desc MyBatis测试
 * @date 2020/6/18 上午11:34
 */
public class MyBatisDemo {
    public static void main(String[] args) throws Exception {
        // 指定mybatis环境配置文件
        String resource = "mybatis-config.xml";
        // 读取配置文件
        InputStream inputStream = Resources.getResourceAsStream(resource);

        // 构建sqlSessionFactory
        SqlSessionFactory sqlSessionFactory
                = new SqlSessionFactoryBuilder().build(inputStream);

        // 获取sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
      
      	System.out.println("MyBatis 环境搭建 OK ");
    }

注意:如果运行出现异常错误,那么可能是 jar 包导入有问题,或者 mybatis-config.xml 编写有语法错误,相信认真核查一下就可以解决。

MyBatis查询操作

首先,在 Maven 工程的main/java/mapper下创建 UserMapper.java 文件,该文件是user的映射器接口,如下:

package mapper;
import entity.UserEntity;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/**
 * @desc User映射器接口
 * @date 2020/6/19 上午8:59
 */
public interface UserMapper {
    /**
     * 根据年龄查询用户信息
     * @param age 年龄
     * @return user 用户实体集合
     */
    public List<UserEntity> selectUserByAge(int age);
}

接着,在 Maven 工程的 resources/mappers下创建 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表示命名空间,填写之前创建的 UserMapp.java 接口包路径 -->
<mapper namespace="mapper.UserMapper">
    <!--结果集映射-->
    <resultMap id="userResultMap" type="entity.UserEntity">
      	<!-- propery表示UserEntity属性名 column表示tb_user表的字段名-->
        <id property="id" column="id" />
        <result property="userName" column="userName" />
        <result property="password" column="password" />
        <result property="name" column="name" />
        <result property="age" column="age" />
        <result property="sex" column="sex" />
        <result property="birthday" column="birthday" />
        <result property="created" column="created" />
        <result property="updated" column="updated" />
    </resultMap>

    <!--select查询语句-->
    <select id="selectUserByAge" resultMap="userResultMap">
        select * from tb_user where age > #{age}
    </select>
</mapper>

在IDEA中安装一个插件MyBatisX

首先出现红鸟图标即在xml文件中其次在接口实现时会出现一个蓝鸟的图标(点击图标会跳转到映射结果集)

然后,在 Maven 工程的 resources/mybatis-config.xml 配置文件中添加 UserMapper.xml 映射文件的路径,如下:

<configuration>
    <!-- 数据库配置 -->
    <environments default="development">
        ...
    </environments>

    <!--配置映射文件路径-->
    <mappers>
        <mapper resource="mappers/UserMapper.xml" />
    </mappers>
</configuration>

最后,在 Maven 工程的 main/java/MyBatisDemo.java 文件中添加代码执行查询操作,如下:

import entity.UserEntity;
import mapper.UserMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.log4j.Logger;
import org.apache.log4j.Priority;

import java.io.InputStream;
import java.util.List;

/**
 * @desc MyBatis测试
 * @date 2020/6/18 上午11:34
 */
public class MyBatisDemo {
    public static void main(String[] args) throws Exception {
        // 指定mybatis环境配置文件
        String resource = "mybatis-config.xml";
        // 读取配置文件
        InputStream inputStream = Resources.getResourceAsStream(resource);

        // 构建sqlSessionFactory工厂对象实例
        SqlSessionFactory sqlSessionFactory
                = new SqlSessionFactoryBuilder().build(inputStream);

        // 获取sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();//工厂模式的工厂方法

        // 执行查询操作语句
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);//通过反射获取接口实现对象
        List<UserEntity> userEntities = userMapper.selectUserByAge(20);

        Logger logger = Logger.getRootLogger();
//        logger.log(Priority.DEBUG,"这是一个debug日志");
        logger.debug("这是一个debug日志");
        logger.info("这是一个info日志");
        logger.warn("这是一个warn日志");
        logger.error("这是一个error日志");


        //关闭sqlSession
        sqlSession.close();

        System.out.println("MyBatis 环境搭建 OK ");
    }
}

CURD操作

create,read,update,delete操作

  • 添加CURD方法
  • 添加CURD接口方法对应的UserMapper.xml映射
  • 使用JUnit单元测试框架测试CURD接口方法

参数传递方式

  • Mapper映射器接口方法参数只有一个且为基本类型

    接口方法:

    public List<UserEntity> selectUserByAge(int age);
    

    映射结果:

    <select id="selectUserByAge" resultMap="userResultMap">
            select * from tb_user where age > #{age};
    </select>
    

    其中 #{参数名} 表示参数占位符,等价于SQL语句的 ?号,这里的 #{age} 对应的就是接口方法 selectUserByAge 的参数。由于只有一个参数,而且是基本类型,所以写成 #{userAge} 或者 #{ageUser} 都无所谓,反正作用是一样的

  • Mapper映射器接口方法参数只有一个且为引用类型

    接口方法:

    public int insertUser(UserEntity user);
    

    映射结果:

    <insert id="insertUser">
       insert into tb_user (id,userName, password, name, age, sex, birthday, created, updated) values
       (null,#{userName},#{password},#{name},#{age},#{sex},#{birthday},now(),now());
    </insert>
    

    接口方法 insertUser 的参数是引用类型,其实传递给 SQL 语句的参数是引用类型的属性值,SQL 语句本身是不支持引用类型的。那引用类型有很多属性(或成员变量),是如何与 SQL 语句的参数一一对应的呢?

    答案是使用 #{引用类型的属性名} ,这里需要注意的是属性名不能写错了,否则就无法与 SQL 语句的参数对应,无法正确传递参数哈。

    public class UserEntity {
        private int id;
        private String userName;
        private String password;
        private String name;
        private int age;
        private int sex;
        private Date birthday;
        private String created;
        private String updated;
    }
    

    由于是自增主键,所以不需要传递引用类型的 id 参数,使用 null 代替,数据库会自动生成主键 id 标识

  • Mapper映射器接口方法参数有两个基本类型

    接口方法:

    public int updateUser(int id, String name);
    

    映射结果:

    <update id="updateUser">
    	  update tb_user set name=#{name} where id=#{id};
    </update>
    

    接口方法 updateUser 有两个参数且都是基本类型,按理说直接使用 #{参数名} 就可以了,不过一运行居然报错,如下:

    ### SQL: update tb_user set name=? where id=?;
    ### Cause: org.apache.ibatis.binding.BindingException: Parameter 'name' not found. Available parameters are [0, 1, param1, param2]
    

    从错误信息描述看,说是参数 name 没有发现,有效的参数是 [0, 1, param1, param2]。意思就是说当遇到不只一个参数时,比如两个参数,就不能用#{参数名}作为占位符,可以用MyBatis提供了两种方式之一。*

    • 方式一#{0} 表示第一个参数 name,#{1} 表示第二个参数 id,#{2} 表示第三个参数...使用如下:

      <update id="updateUser">
      	  update tb_user set name=#{0} where id=#{1};
      </update>
      
    • 方式二#{param1} 表示第一个参数 name,#{param2} 表示第二个参数 id,#{param3} 表示第三个参数...使用如下:

      <update id="updateUser">
      	  update tb_user set name=#{param1} where id=#{param2};
      </update>
      
    • 方式三:给接口方法的参数取别名,只要参数别名和 #{参数名} 相同就可以了。使用如下:

      // @Param("id")表示给参数 int id 取别名为id,@Param("name") 表示给参数 name 取别名为name
      public int updateUser(@Param("id") int id,@Param("name") String name);
      
      <update id="updateUser">
      	  update tb_user set name=#{name} where id=#{id};
      </update>
      

      以上三种 MyBatis 参数的传递方式,哪种项目开发中比较常用呢?答案是第三种方式。理由是这种方式的代码可读性更好。想一想上面举例中,是#{name},#{id}作为参数占位符意思让人一目了然,还是#{0},#{1},#{param1},#{param2}呢?答案应该不言而喻。

  • Mapper映射器接口方法参数有两个引用类型

    接口方法:

    public List<UserEntity> selectUserByAgeAndSex(@Param("userOne") UserEntity userOne,@Param("userTwo") UserEntity userTwo);
    

    映射结果1:

    <select id="selectUserByAgeAndSex" resultMap="userResultMap">
      	select * from tb_user where age > #{userOne.age} and sex = #{userTwo.sex};
    </select>
    

    映射结果2:

    <select id="selectUserByAgeAndSex" resultMap="userResultMap">
            select * from tb_user where age > #{param1.age} and sex = #{param2.sex};
    </select>
    

    以上两种映射方式都可以,但是如果没有为两个参数取 @Param("userOne") 和 @Param("userTwo") 别名的话,那么就只有映射结果2可以了,映射结果1将会报错。

    注: #{0}、#{1}这种参数占位符的方式只适用于参数是基本类型,不适用于参数是引用类型。

  • Mapper映射器接口方法参数有多个(包括基本类型和引用类型)

    接口方法:

    public List<UserEntity> selectUserByNameAndAge(@Param("name") String name, @Param("user") UserEntity user);
    

    映射结果1:

    <select id="selectUserByNameAndAge" resultMap="userResultMap">
       select * from tb_user where name = #{name} and age > #{user.age};
    </select>
    

    映射结果2:

    <select id="selectUserByNameAndAge" resultMap="userResultMap">
        select * from tb_user where name = #{param1} and age > #{param2.age};
    </select>
    

模糊查询的方式(四种)---推荐使用第三种

<select id="selectByName" resultType="EmployeeEntity">
    select * from tb_employee where name like #{name}
</select>
SqlSession sqlSession = MyBatisUtil.getSession();
IEmpolyeeDao empolyeeDao = sqlSession.getMapper(IEmpolyeeDao.class);
EmployeeEntity = IEmpolyeeDao.selectByName("%"+"张"+"%");
MyBatisUtil.closeSesion(sqlSession);

这种方式可以实现模糊查询,但是有一点不方便的地方就是在调用接口 selectByName() 方法传参时需要手动的添加 "%" 号通配符,有些麻烦。

  • 方式一:手动添加"%"通配符

  • xml配置:

  • <select id="fuzzyQuery" resultType="com.bin.pojo.Book">
        select * from mybatis.book where bookName like #{info};
    </select>
    
  • @Test
    public void fuzzyQuery(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BookMapper mapper = sqlSession.getMapper(BookMapper.class);
        List<Book> books = mapper.fuzzyQuery("%萨%");
        for (Book book : books) {
            System.out.println(book);
        }
        sqlSession.close();
    }
    
  • 注意:需要手动添加"%"通配符,显然这种方式很麻烦,并且如果忘记添加通配符的话就会变成普通的查询语句,匹配全部字符查询。

  • 缺点:麻烦 易出错

  • 方式二:在xml配置文件中添加"%"通配符,拼接字符串形式

  • <select id="fuzzyQuery" resultType="com.bin.pojo.Book">
        select * from mybatis.book where bookName like '%${info}%';
    </select>
    
  • 注意:在mapper.xml配置文件中添加"%"通配符,但是需要用单引号将其包裹住,但是用单引号裹住之后#{}就无法被识别,要改成${}这种拼接字符串的形式。虽然通过方式二优化了方式一的缺点,但同时也造成了SQL安全性的问题,也就是用户可以进行SQL注入。

  • 缺点:不安全,可进行SQL注入

  • 方式三:在xml配置文件中添加"%"通配符,借助concat函数(一个mysql函数)

  • <select id="fuzzyQuery" resultType="com.bin.pojo.Book">
        select * from mybatis.book where bookName like 
        concat('%',#{info},'%');
    </select>
    
  • 注意:解决了SQL注入且能在配置文件中写"%"通配符的问题,完美实现了模糊查询

  • 优点:安全方便

  • 方式四:与方式三一样使用mysql函数,但使的用是${}形式,不过需要用单引号包裹住

  • <select id="fuzzyQuery" resultType="com.bin.pojo.Book">
        select * from mybatis.book where bookName like 
        concat('%','${info}','%');
    </select>
    
  • 缺点:****$有sql注入风险

  • 总结:#{}是预编译处理,mybatis在处理#{}时,会将其替换成"?",再调用PreparedStatement的set方法来赋值。
    ${}是拼接字符串,将接收到的参数的内容不加任何修饰的拼接在SQL语句中,会引发SQL注入问题。

ResultMap标记

(MyBatis中最重要最强大也是最复杂的标记)

<!-- resultMap 结果集映射-->
<resultMap id="userResultMap" type="entity.UserEntity" autoMapping="true">
        <!-- propery表示UserEntity属性名,column表示tb_user表字段名-->
        <id property="id" column="id" />
        <result property="userName" column="user_name" />
        <result property="password" column="password" />
        <result property="name" column="name" />
        <result property="age" column="age" />
        <result property="sex" column="sex" />
        <result property="birthday" column="birthday" />
        <result property="created" column="created" />
        <result property="updated" column="updated" />
</resultMap>

<!-- 使用 resultMap 标记的结果集映射-->
<select id="selectUserByAge" parameterType="int" resultMap="userResultMap">
        select * from tb_user where age > #{age}
</select>

  • resultMap 标签:定义 结果集 ORM 映射规则
  • id 属性:当前名称空间下的唯一标识(resultMap 属性值填写 id 属性引用 resultMap 定义的结果集映射)
  • type 属性:Java 实体类全名
  • autoMapping 属性:自动映射开关
  • id 子标签:数据库主键字段与Java 实体类主键标识属性映射
  • result 子标签:数据库普通字段与 Java 实体类普通属性映射
  • property 属性:Java 实体类属性名
  • column 属性:数据库字段名

这些标签和属性的作用一目了然,不用做过多解释,但 autoMapping 属性的作用大家可能不太明白。

如果 autoMapping 属性设置为 true,表示开启自动映射开关,意思就是如果数据库字段名和 Java 实体类属性名相同,那么就可以不用使用 id 子标签或 result 子标签手动映射了。

MyBatis 会自动完成映射这些相同的数据库字段名。至于,不相同的数据库字段名,那还是麻烦你手动映射一下哈。

还记得之前讲过的 resultType 属性,它的作用也是完成自动映射,不过它要求数据库表所有字段名和 Java 实体类属性名必须全部相同,否则有与 Java 实体类属性名不同的字段名无法正常映射的。

所以,resultMap 标记 和 autoMapping 属性一起使用,相当于让 resultMap 的一个一个数据库字段纯手工映射变为半自动映射啦,一方面不失灵活性,一方面不失简洁性。

开启 autoMapping 属性,以上 resultMap 标记可以改写如下,是不是简洁多了。

<!-- resultMap 结果集映射-->
<resultMap id="userResultMap" type="entity.UserEntity" autoMapping="true">
        <result property="userName" column="user_name" />
</resultMap>

实体类属性名与数据库字段名不一致

  • Java 实体类属性名与数据库表字段名不一致的问题

  • 完成复杂(或高级)SQL 操作,比如联表查询(一对一、一对多或多对多)、子查询、分组查询等当实体类属性名和数据库表字段名不同时,有两种情况如下:

  • 情况一:如果数据库字段是经典数据库命名规则,Java 实体类属性名是驼峰命名规则,如下:

​ 数据库字段:user_name

​ Java 属性名:userName

​ 这种情况,有两种解决办法:

​ 一种是使用 resultMap 标记,手动设置数据库字段和实体类属性名的映射关系,如下:

<result property="userName" column="user_name" />

​ 一种是使用 resultType 属性,自动进行结果集映射,不过需要 settings 设置打开自动驼峰命名规则映射开关,如下:

<!-- 开启自动驼峰命名规则映射开关 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
  • 情况二:如果数据库字段和 Java 实体类属性名完全不一致,如下:

​ 数据库字段:my_user_name

​ Java 属性名:userName

​ 这种情况,只有一种解决办法,那就是 resultMap 标记,如下:

<result property="userName" column="my_user_name" />
  <resultMap id="orderResultMap" type="entity.OrderEntity">
        <id property="id" column="id"/>
        <result property="userId" column="user_id"/>
        <result property="createTime" column="create_time"/>
        <result property="updateTime" column="update_time"/>
    </resultMap>
  <!--第一种方式resultMap-->
  <select id="getOrderById" resultMap="orderResultMap"> 
           SELECT * FROM tb_order WHERE id = #{id}
  </select>
  <!--二三种方式都是resultType-->
   <select id="getOrderById" resultType="entity.OrderEntity">
        <!--第二种取别名-->
       SELECT id,user_id as userId,name,create_time as createTime,update_time as updateTime FROM tb_order WHERE id = #{id}
        <!--第三种方式打开驼峰命名法开关-->
        select * from tb_order where id = #{id}
    </select>

在mybatis-config.xml文件中

<settings>
         <!--是否开启自动加载驼峰命名规则映射映射文件 -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

多表查询(高级查询)

环境搭建

  • 数据库的表之间必须有一定的关系并且必须为多表
  • 在IDEA中建立对应的实体类(如何在实体类中体现表之间的关系呢?) ---- 在一个实体类中引用另一个实体类的属性
  • 建立映射接口
  • 映射结果集,对应的映射文件即xml
  • 全局配置(mybatis-config.xml中)配置对应的映射文件

一 对 一

查询条件

public interface GameMapper {
    /**
     * 根据角色ID查询账号信息
     * @param id 角色Id
     * @return 角色实体对象
     */
    public RoleEntity selectRoleById(int id);
    /**
     * 根据游戏名查询游戏账号
     * @param name 游戏名
     * @return 游戏实体类
     */
    public GameEntity selectGameByName(String name);
    /**
     * 根据玩家名查询游戏
     * @param name 玩家名
     * @return 玩家实体类
     */
    public PlayerEntity selectPlayerByName(String name);

}

关联查询(两种)

  • 第一种

            <result property="account.id" column="aid" />
            <result property="account.username" column="username" />
            <result property="account.password" column="password" />
    
  • 现在我们暂时先抛开 MyBatis 框架,直接从数据库出发写一写关联查询的 SQL 语句,如下:

    select r.*,a.* from tb_role as r join tb_account as a on r.account_id=a.id where r.id=1
    

    另外,还有一种不使用 join 关键字的 SQL 语句写法,如下:

    select r.*,a.* from tb_role as r,tb_account as a where r.account_id=a.id and r.id=1
    

    第一种写法,使用 join 关键字,本质上是采用的内连接(inner join)。

    第二种写法,不使用 join 关键字,本质上是采用交叉连接(cross join),也即生成两表的笛卡尔积,得到的记录相当于两表记录的乘积。

    以上两种写法查询结果是相同的,但推荐使用第一种,因为第一种性能比第二种高,特别是在有大表的情况下。

    理由是第二种交叉连接将产生更多的记录,然后通过 where 后的 r.account_id=a.id 条件过滤不需要的记录,而第一种内连接会直接过滤不需要的记录,所以执行效率更高。

我们回到 MyBatis 框架,看一下在 XML 映射文件中,如何实现关联查询映射。

首先,我们需要建立 RoleEntity 实体类与 AccountEntity 实体类之间的关联关系,如下:

public class RoleEntity {
    private int id;
    private String profession;
    private int rank;
    private int money;
    private AccountEntity account; //关联引用属性
    ...
}

这样,通过账号名查询的账号信息就可以映射到 account 属性中。注意 account 属性的 get 和 set 方法要记得添加上去,还有 toString 方法要重写一下,添加 account 属性的打印信息。

现在,我们来编写映射文件(GameMapper.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="mapper.GameMapper">
    <resultMap id="roleResultMap" type="entity.RoleEntity">
        <id property="id" column="id" />
        <result property="profession" column="profession" />
        <result property="rank" column="rank" />
        <result property="money" column="money" />
        <result property="account.id" column="aid" />
        <result property="account.username" column="username" />
        <result property="account.password" column="password" />
    </resultMap>

    <select id="selectRoleById" resultMap="roleResultMap">
        select r.*,a.id as aid,a.user_name,a.password from tb_role as r join tb_account as a on r.account_id=a.id where r.id=#{id}
    </select>
</mapper>

这个地方使用到了级联赋值,多级之间用.进行引用,此处我们只有一级,可以有很多级

  • 注意事项:

    select r.*,a.*from tb_role as r join tb_account as a on r.account_id=a.id where r.id=#{id} 写法存在的问题:

    这会存在两个相同字段名 id,结果集映射时 accout 的 id 值会被 role 的 id 值所覆盖

  • 第二种

           <!-- association:用于映射关联查询单个对象信息
    		         property:将关联查询的账号信息映射到属性 account 上 -->
            <association property="account" javaType="entity.AccountEntity">
                <id property="id" column="aid" />
                <result property="userName" column="user_name" />
                <result property="password" column="password" />
            </association>
    

    和之前单表映射相比,没什么太大差别,就是多了 association 子标记以及相应的内容罢了。

    意思很也简单,就是将关联查询结果中的账号信息,具体而言就是 a.id,a.user_name,a.password ,映射到 AccountEntity 实例中,也就是 RoleEntity.account 属性。

    现在,我们来编写映射文件中 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="mapper.GameMapper">
        <resultMap id="roleResultMap" type="entity.RoleEntity">
            <id property="id" column="id" />
            <result property="profession" column="profession" />
            <result property="rank" column="rank" />
            <result property="money" column="money" />
            <!-- association:用于映射关联查询单个对象信息
    		         property:将关联查询的账号信息映射到属性 account 上 -->
            <association property="account" javaType="entity.AccountEntity">
                <id property="id" column="aid" />
                <result property="userName" column="user_name" />
                <result property="password" column="password" />
            </association>
        </resultMap>
    
        <select id="selectRoleById" resultMap="roleResultMap">
            select r.*,a.id as aid,a.user_name,a.password from tb_role as r join tb_account as a on r.account_id=a.id where r.id=#{id}
        </select>
    </mapper>
    
    • 注:****autoMapping 属性:自动映射开关,关联查询默认 false,当设置为 true 则当字段名和实体类属性名相同时可以自动映射

    • mybatis-config.xml文件中打开

      <!--数据库配置-->
      <!--设置数据库url地址-->
        <property name="url" value="jdbc:mysql://localhost:3306/sgs?useUnicode=true&amp;characterEncoding=UTF-8&amp;useSSL=false&amp;allowPublicKeyRetrieval=true&amp;serverTimezone=GMT%2B8&amp;allowMultiQueries=true"/>
      

      最后,我们在 MyBatisTest 中添加一个单元测试方法,如下:

      @Test
      public void selectRoleByAccountNameTest() {
          RoleEntity roleEntity = gameMapper.selectRoleById(1);
          System.out.println(roleEntity);
      
          Assert.assertNotNull(roleEntity);
      }
      

      执行测试,结果如下:

      2020-07-15 10:49:28,860 [main] [mapper.GameMapper.selectRoleById]-[DEBUG] ==>  Preparing: select r.*,a.id,a.user_name,a.password from tb_role as r join tb_account as a on r.account_id=a.id where r.id=? 
      2020-07-15 10:49:28,954 [main] [mapper.GameMapper.selectRoleById]-[DEBUG] ==> Parameters: 1(Integer)
      2020-07-15 10:49:28,985 [main] [mapper.GameMapper.selectRoleById]-[DEBUG] <==      Total: 1
      RoleEntity{id=1, profession='战士', rank=10, money=2000, account=AccountEntity{id=1, userName='潇洒哥', password='12345'}}
      

      这样,我们通过游戏角色ID查询到了游戏账号信息,并封装在 RoleEntity 对象的 account 属性中

子查询(两种)

  • 第一种

            <!-- association:用于映射关联查询单个对象信息
    		    property:将关联查询的账号信息映射到属性 account 上
     			column:传递子查询参数
    			select:子查询id
    		-->
            <association property="account" javaType="entity.AccountEntity"
                         column="account_id" select="selectAccountById">
            </association>
    

    老规矩,现在我们暂时先抛开 MyBatis 框架,直接从数据库出发写一写子查询的 SQL 语句,如下:

    select * from tb_account where id=(select account_id from tb_role where id=1)
    

    这条子查询 SQL 语句由两条 select 语句组成,不用过多解释了,应该很容易理解。

    现在,我们回到 MyBatis 框架,之前关联查询时我们已经建立 RoleEntity 实体类与 AccountEntity 实体类之间的关联关系,所以,这里我们直接来编写映射文件中 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="mapper.GameMapper">
        <resultMap id="roleResultMap" type="entity.RoleEntity">
            <id property="id" column="id" />
            <result property="profession" column="profession" />
            <result property="rank" column="rank" />
            <result property="money" column="money" />
          
            <!-- association:用于映射关联查询单个对象信息
    		         property:将关联查询的账号信息映射到属性 account 上
     						 column:传递子查询参数
    						 select:子查询id
    				-->
            <association property="account" javaType="entity.AccountEntity"
                         column="account_id" select="selectAccountById">
            </association>
        </resultMap>
    
        <select id="selectRoleById" resultMap="roleResultMap">
            select * from tb_role where id=#{id}
        </select>
        <select id="selectAccountById" resultType="entity.AccountEntity">
            select * from tb_account where id=#{accountId}
        </select>
    </mapper>
    

    以上可以看到,子查询和关联查询不一样的地方在于 association 标记多了 column 和 select 这两个属性。

    • column 的值是 account_id,这是 tb_role 表的外键 ID 字段名,意思是将该字段名对应的字段值作为参数传递给指定的子查询
    • select 的值是 selectAccountById,这是子查询 select 语句的ID,表示指定 ID 定义的子查询,也就是 select * from tb_account where id=#{accountId} 这条查询语句。这里的参数 #{accountId} 对应的就是column 的值

    以上子查询的参数只有一个,那么如果子查询的参数不止一个,又该怎么办呢?比如是复合主键。如果要处理复合主键,可以使用column= "{prop1=col1,prop2=col2}" ,prop表示类属性名,col表示表字段名。

    执行测试,结果如下:

    2020-07-15 10:57:56,314 [main] [mapper.GameMapper.selectRoleById]-[DEBUG] ==>  Preparing: select * from tb_role where id=? 
    2020-07-15 10:57:56,360 [main] [mapper.GameMapper.selectRoleById]-[DEBUG] ==> Parameters: 1(Integer)
    2020-07-15 10:57:56,392 [main] [mapper.GameMapper.selectAccountById]-[DEBUG] ====>  Preparing: select * from tb_account where id=? 
    2020-07-15 10:57:56,392 [main] [mapper.GameMapper.selectAccountById]-[DEBUG] ====> Parameters: 1(Integer)
    2020-07-15 10:57:56,392 [main] [mapper.GameMapper.selectAccountById]-[DEBUG] <====      Total: 1
    2020-07-15 10:57:56,392 [main] [mapper.GameMapper.selectRoleById]-[DEBUG] <==      Total: 1
    RoleEntity{id=1, profession='战士', rank=10, money=2000, account=AccountEntity{id=1, userName='null', password='12345'}}
    

    结果和关联查询一样,而且从打印调试信息可以看到,子查询是先后执行了两条简单的 select 语句。

    这里还有一个小问题,就是账号信息的 userName 属性值是 null。为何会如此呀,原因是 tb_account 字段名是user_name,AccountEntity 实体类属性名是 userName,无法使用 resultType 自动映射。

    解决办法有两个:

    • 子查询结果集映射不使用 resultType 自动映射,改为 resultMap 手动映射,如下:

      <resultMap id="accountResultMap" type="entity.AccountEntity">
         <id property="id" column="id" />
         <result property="userName" column="user_name" />
         <result property="password" column="password" />
      </resultMap>
      <select id="selectAccountById" resultMap="accountResultMap">
              select * from tb_account where id=#{accountId}
      </select>
      
    • 在全局配置文件 mybatis-config.xml 开启 settings 开关

      <configuration>  
        <settings>
           <!-- 开启自动驼峰命名规则映射开关 -->     
           <setting name="mapUnderscoreToCamelCase" value="true"/>
        </settings>        
        ...
      </configuration>
      

    结果如下:

    RoleEntity{id=1, profession='战士', rank=10, money=2000, account=AccountEntity{id=1, userName='潇洒哥', password='12345'}}
    

    userName 已经有值了,说明问题得以解决

  • 第二种

子查询方式一种给第二个查询传递了一个参数,如果需要给第二个查询传递多个参数怎么办呢?

<association property="属性" select="查询对应的select的id" 
             column="{key1=父查询字段1,key2=父查询字段2,key3=父查询字段3}" />

这种相当于给子查询传递了一个 map,子查询中 需要用过 map 的 key 获取对应的条件

<resultMap id="roleResultMap" type="entity.RoleEntity">
    <id property="id" column="id" />
    <result property="profession" column="profession" />
    <result property="rank" column="rank" />
    <result property="money" column="money" />

    <!-- association:用于映射关联查询单个对象信息
           property:将关联查询的账号信息映射到属性 account 上
        column:传递子查询参数
       select:子查询id
    -->
    <association property="account" javaType="entity.AccountEntity"
                 column="{aid=account_id,rid=id}" select="selectAccountById">
    </association>
</resultMap>

一 对 多

查询条件

根据游戏名称,查询游戏账号信息

我们在之前创建的映射器接口 GameMapper.java 中添加接口方法,如下:

	/**
     * 根据游戏名查询游戏账号
     * @param name 游戏名
     * @return 游戏实体类
     */
    public GameEntity selectGameByName(String name);

接下来,我分别演示关联查询和子查询方式实现接口方法的映射。

关联查询方式

现在我们暂时先抛开 MyBatis 框架,直接从数据库出发写一写关联查询的 SQL 语句,如下:

select g.*,a.* from tb_game as g join tb_account as a on g.id=a.game_id where g.name ='英雄联盟'

现在,我们回到 MyBatis 框架,看一下在 XML 映射文件中,如何实现关联查询映射。

首先,我们需要建立 GameEntity 实体类与 AccountEntity 实体类之间的关联关系,如下:

public class GameEntity {
    private int id;
    private String name;
    private String type;
    private String operator;
    private List<AccountEntity> accounts; //关联引用游戏账号集合
}

这样,通过游戏名查询的账号信息就可以映射到 accounts 属性中。注意 accounts 属性的 get 和 set 方法要记得添加上去,还有 toString 方法要重写一下,添加 accounts 属性的打印信息。

你可能有疑惑,这里为何要使用 List 集合呢?原因是一款游戏对应的账号信息可能有多个,而 MyBatis 可以通过使用 resultMap 的 collection 标记将关联查询的多条记录映射到一个 List 集合属性中。

现在,我们来编写映射文件中 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="mapper.GameMapper">
    <resultMap id="gameResultMap" type="entity.GameEntity">
        <id property="id" column="id" />
        <result property="name" column="name" />
        <result property="type" column="type" />
        <result property="operator" column="operator" />
      
       <!-- collection:一对多映射,关联当前分类下产品信息 
					  property:映射集合结果
					  ofType:结果集类型 -->
        <collection property="accounts" ofType="entity.AccountEntity">
            <id property="id" column="a.id" />
            <result property="userName" column="user_name" />
            <result property="password" column="password" />
        </collection>
    </resultMap>
    <select id="selectGameByName" resultMap="gameResultMap">
        select g.*,a.id as aid,a.user_name,a.password from tb_game as g join tb_account as a on g.id=a.game_id where g.name =#{name}
    </select>
</mapper>

以上和一对一关联查询相比,association 标记改为 collection 标记,表示是一对多映射;javaType 属性改为ofType 属性,表示集合里的元素类型。除此以外,和一对一关联查询差不多。

最后,我们在 MyBatisTest 中添加一个单元测试方法,如下:

	@Test
    public void selectGameByNameTest() {
        GameEntity gameEntity = gameMapper.selectGameByName("英雄联盟");
        System.out.println(gameEntity);

        Assert.assertNotNull(gameEntity);
    }

执行单元测试方法,结果如下:

2020-07-15 18:34:05,260 [main] [mapper.GameMapper.selectGameByName]-[DEBUG] ==>  Preparing: select g.*,a.* from tb_game as g join tb_account as a on g.id=a.game_id where g.name =? 
2020-07-15 18:34:05,307 [main] [mapper.GameMapper.selectGameByName]-[DEBUG] ==> Parameters: 英雄联盟(String)
2020-07-15 18:34:05,354 [main] [mapper.GameMapper.selectGameByName]-[DEBUG] <==      Total: 2
GameEntity{id=1, name='英雄联盟', type='MOBA', operator='腾讯游戏', accounts=[AccountEntity{id=1, userName='潇洒哥', password='12345'}, AccountEntity{id=4, userName='进击巨人', password='11111'}]}

子查询方式

首先,我们暂时先抛开 MyBatis 框架,直接从数据库出发写一写子查询的 SQL 语句,如下:

select * from tb_account where game_id = (select id from tb_game where name ='英雄联盟')

接着,这里我们直接来编写映射文件中 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="mapper.GameMapper">
    <resultMap id="gameResultMap" type="entity.GameEntity">
        <id property="id" column="id" />
        <result property="name" column="name" />
        <result property="type" column="type" />
        <result property="operator" column="operator" />
      
     		<!-- collection:用于映射关联查询多个对象信息
		         property:将关联查询的账号信息映射到属性 accounts 上
 						 column:传递子查询参数
						 select:子查询id
				-->
        <collection property="accounts" ofType="entity.AccountEntity"
            column="id" select="selectAccountById" />
    </resultMap>
  
    <select id="selectGameByName" resultMap="gameResultMap">
        select * from tb_game where name =#{name}
    </select>
    <select id="selectAccountById" resultType="entity.AccountEntity">
        select * from tb_account where game_id=#{gameId}
    </select>
</mapper>

执行测试,结果如下:

2020-07-15 21:25:11,086 [main] [mapper.GameMapper.selectGameByName]-[DEBUG] ==>  Preparing: select * from tb_game where name =? 
2020-07-15 21:25:11,164 [main] [mapper.GameMapper.selectGameByName]-[DEBUG] ==> Parameters: 英雄联盟(String)
2020-07-15 21:25:11,211 [main] [mapper.GameMapper.selectAccountById]-[DEBUG] ====>  Preparing: select * from tb_account where game_id=? 
2020-07-15 21:25:11,211 [main] [mapper.GameMapper.selectAccountById]-[DEBUG] ====> Parameters: 1(Integer)
2020-07-15 21:25:11,211 [main] [mapper.GameMapper.selectAccountById]-[DEBUG] <====      Total: 2
2020-07-15 21:25:11,211 [main] [mapper.GameMapper.selectGameByName]-[DEBUG] <==      Total: 1
GameEntity{id=1, name='英雄联盟', type='MOBA', operator='腾讯游戏', accounts=[AccountEntity{id=1, userName='潇洒哥', password='12345'}, AccountEntity{id=4, userName='进击巨人', password='11111'}]}

多 对 多

查询条件:根据玩家名,查询游戏信息

我们在之前创建的映射器接口 GameMapper.java 中添加接口方法,如下:

	/**
     * 根据玩家名查询游戏
     * @param name 玩家名
     * @return 玩家实体类
     */
    public PlayerEntity selectPlayerByName(String name);

接下来,我分别演示关联查询和子查询方式实现接口方法的映射。

关联查询方式

现在我们暂时先抛开 MyBatis 框架,直接从数据库出发写一写关联查询的 SQL 语句,如下:

select p.*,g.* from tb_player as p join tb_player_game as p_g on p.id = p_g.player_id join tb_game as g on g.id = p_g.game_id where p.name = '张三' 

这条 SQL 语句有点长,涉及三表关联查询,因为多对多相比一对多而言,多了一张中间表哈。

我们在数据库中执行这条 SQL 语句,结果如下

现在,我们回到 MyBatis 框架,看一下在 XML 映射文件中,如何实现关联查询映射。

首先,我们需要建立 PlayerEntity 实体类 与 GameEntity 实体类之间的关联关系,如下:

public class PlayerEntity {
    private int id;
    private String name;
    private int age;
    private int sex;
    private List<GameEntity> games;
}

这样,通过玩家名查询的游戏信息就可以映射到 games 属性中。对了,set 和 get 方法以及 toString 方法自己补上哈。

现在,我们来编写映射文件中 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="mapper.GameMapper">
    <resultMap id="playerResultMap" type="entity.PlayerEntity">
        <id property="id" column="id" />
        <result property="name" column="name" />
        <result property="age" column="age" />
        <result property="sex" column="sex" />

        <collection property="games" ofType="entity.GameEntity">
            <id property="id" column="id" />
            <result property="name" column="name" />
            <result property="type" column="type" />
            <result property="operator" column="operator" />
        </collection>
    </resultMap>
    <select id="selectPlayerByName" resultMap="playerResultMap" >
        select p.*,g.* from tb_player as p
        join tb_player_game as p_g on p.id = p_g.player_id
        join tb_game as g on g.id = p_g.game_id where p.name = #{name}
    </select>
</mapper>

不过多说,和一对多关联映射差不多。

最后,我们在 MyBatisTest 中添加一个单元测试方法,如下:

 		@Test
    public void selectPlayerByNameTest() {
        PlayerEntity playerEntity = gameMapper.selectPlayerByName("张三");
        System.out.println(playerEntity);

        Assert.assertNotNull(playerEntity);
    }

执行测试,结果如下:

2020-07-16 21:57:18,545 [main] [mapper.GameMapper.selectPlayerByName]-[DEBUG] ==>  Preparing: select p.*,g.* from tb_player as p join tb_player_game as p_g on p.id = p_g.player_id join tb_game as g on g.id = p_g.game_id where p.name = ? 
2020-07-16 21:57:18,623 [main] [mapper.GameMapper.selectPlayerByName]-[DEBUG] ==> Parameters: 张三(String)
2020-07-16 21:57:18,669 [main] [mapper.GameMapper.selectPlayerByName]-[DEBUG] <==      Total: 2
PlayerEntity{id=1, name='张三', age=23, sex=1, games=[GameEntity{id=1, name='英雄联盟', type='MOBA', operator='腾讯游戏', accounts=null}, GameEntity{id=2, name='绝地求生', type='TPS', operator='蓝洞游戏', accounts=null}]}

可以思考一下,如果这里需要打印账号信息,你可以尝试一下能否自己独立搞定。

子查询方式

我们暂时先抛开 MyBatis 框架,直接从数据库出发写一写子查询的 SQL 语句,如下:

select * from tb_game where id in(
  select game_id from tb_player_game where player_id = (
  	select id from tb_player where name ='张三'
  )
)

这条 SQL 语句涉及三张表,两个子查询,由于子查询返回多个 id,所以用 in

接着,这里我们直接来编写映射文件中 SQL 语句映射,如下:

 		<resultMap id="playerResultMap" type="entity.PlayerEntity">
        <id property="id" column="id" />
        <result property="name" column="name" />
        <result property="age" column="age" />
        <result property="sex" column="sex" />

        <collection property="games" ofType="entity.GameEntity" column="id" select="selectGameById" />
    </resultMap>

    <select id="selectPlayerByName" resultMap="playerResultMap" >
        select * from tb_player where name = #{name}
    </select>

    <select id="selectGameById" resultType="entity.GameEntity">
        select * from tb_game where id in (select game_id from tb_player_game where player_id=#{id})
    </select>

执行测试,结果如下:

2020-07-16 22:59:17,601 [main] [mapper.GameMapper.selectPlayerByName]-[DEBUG] ==>  Preparing: select * from tb_player where name = ? 
2020-07-16 22:59:17,647 [main] [mapper.GameMapper.selectPlayerByName]-[DEBUG] ==> Parameters: 张三(String)
2020-07-16 22:59:17,679 [main] [mapper.GameMapper.selectGameById]-[DEBUG] ====>  Preparing: select * from tb_game where id in (select game_id from tb_player_game where player_id=?) 
2020-07-16 22:59:17,679 [main] [mapper.GameMapper.selectGameById]-[DEBUG] ====> Parameters: 1(Integer)
2020-07-16 22:59:17,679 [main] [mapper.GameMapper.selectGameById]-[DEBUG] <====      Total: 2
2020-07-16 22:59:17,679 [main] [mapper.GameMapper.selectPlayerByName]-[DEBUG] <==      Total: 1
PlayerEntity{id=1, name='张三', age=23, sex=1, games=[GameEntity{id=1, name='英雄联盟', type='MOBA', operator='腾讯游戏', accounts=null}, GameEntity{id=2, name='绝地求生', type='TPS', operator='蓝洞游戏', accounts=null}]}

标签:语句,name,映射,where,查询,sql,MyBatis,tb,id
From: https://www.cnblogs.com/yangcurry/p/18474927

相关文章

  • Hive为什么依赖Mysql
    Hive之所以需要MySQL依赖,主要是因为Hive使用MySQL(或其他关系型数据库)来存储其元数据。以下是详细的解释:元数据存储Hive在执行查询和存储数据时,需要维护表的结构、列的数据类型、表之间的关系、分区信息等元数据。这些元数据通常存储在一个称为Metastore的地方。为了......
  • 三、MyBatis实践:提高持久层数据处理效率(1)(包含mybatis下载官网)
    一、Mybatis简介1.1简介https://mybatis.org/mybatis-3/zh/index.htmlMyBatis最初是Apache的一个开源项目iBatis,2010年6月这个项目由ApacheSoftwareFoundation迁移到了GoogleCode。随着开发团队转投GoogleCode旗下,iBatis3.x正式更名为MyBatis。代码于2013年11月迁移......
  • 数据库性能调优:定位Slow SQL!
    定位慢SQL(SlowSQL)是数据库性能调优中的一个重要任务,目的是找到和优化那些执行时间较长的SQL查询。以下是常用的定位慢SQL的方法和步骤:1.使用数据库自带工具大多数数据库管理系统(DBMS)提供了内置的工具和视图来帮助定位慢SQL。以下是一些主要数据库的常用工具:MySQL慢......
  • 解决mybatis用Map返回的字段全变大写的问题
    mybatis通常情况都是用javabean作为resultType的对象,但是有时也可以使用Map去接收。${value}如果使用Map,返回来的字段名全是大写,处理方法Selectnameas“name”fromv_zhyl_zxzf_hqyzflb加上字段别名加上双引号就可以了补充知识:Mybatis查询返回类型为Map空值字段不显示项目使......
  • Java工程师必备的20条SQL最佳实践详解
    在Java开发中,SQL是处理数据库交互的核心技能。高效的SQL查询不仅能够提升应用程序的性能,还能减少资源消耗和提高用户体验。以下是Java工程师必备的20条SQL最佳实践,每条都附有代码示例和详细解释。1.使用索引索引可以显著提高查询速度。为经常用于查询条件、排序和连接的......
  • mysql当数据库发现了慢sql怎么定位?--待验证
    1、应用侧生成链路id。使用skywalking2、mybatis写拦截器,sql里面加入链路id`@Intercepts({@Signature(type=StatementHandler.class,method="prepare",args={Connection.class,Integer.class})})publicclassSqlStatementInterceptorimplementsInterceptor{......
  • 【高级SQL 十条调优技巧含实例可执行命令】
    高级SQL技巧是在SQL查询和操作方面进行更高级的优化和功能实现的技巧。以下是一些常见的高级SQL技巧:使用窗口函数:窗口函数是一种强大的SQL功能,它允许在查询结果上执行聚合函数,同时保留原始数据行。使用窗口函数可以实现排序、分组和计算行号等功能。窗口函数:SELE......
  • Windows环境PgSql自动备份脚本
    PgSql脚本如下保存到指定路径并添打成压缩包@echooffsetlocalenabledelayedexpansionsetpg_path=D:\PgSql\bin REM数据库Bin路径setbase_backup_path=D:\backup_pgsql REM备份路径setdb_name=pgsql REM数据库名称setuser=postgres REM数据库账户名setPGPAS......
  • PostgreSQL中对日期时间进行分组
    PostgreSQL在PostgreSQL中对日期时间进行分组|极客教程(geek-docs.com)#按年月日时分组SELECTextract(yearfromcreated_time)asyear,extract(monthfromcreated_time)asmonth,extract(dayfromcreated_time)asday,extract(hourfromcreated_time)ashour,c......
  • SpringBoot 项目的方法名是否添加@Transactional注解,以及SQL语句(SQLServer数据库)是
    项目改用SpringDataJDBC并手动配置DataSource之后,@Transactional注解一直不起作用。这两天研究了一下,注解不起作用,主要是没有配置TransactionManager的事,配置完TransactionManager之后,@Transactional注解就起作用了。但是配置完又发现,用jdbcTemplate.queryForList()方法执......