框架阶段:mybatis

RAG——从0到1快速搭建RAG应用 本文介绍了基于LangChain框架构建RAG(检索增强生成)应用的技术方案,涵盖核心模块选型与实现流程。技术栈包括:LangChain应用框架、pypdf文档解析、RecursiveCharacterTextSplitter文本分块、bge-small-zh-v1.5向量模型、Faiss向量库和通义千问大模型。文章详细说明了开发环境配置步骤,包括虚拟环境创建、依赖库安装和模型下载。核心代码分为索引、检索、生成三大流程,索引流程完成PDF文档解析、分块和向量化存储;检索流程实现查询向量化和相似度匹配;生成流 阅读详情

1. mybatis简介

MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以对配置和原生Map使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

2. 通过入门案例了解mybatis

2.1 mybatis环境

  1. 新建maven项目,导入mybatis相关的依赖
<!--    mybaits-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.5</version>
    </dependency>
<!--    mysql-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.6</version>
    </dependency>
<!--    log4j-->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
<!--    junit-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13</version>
    </dependency>
  1. 数据库环境
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) NOT NULL COMMENT '用户名称',
  `birthday` date DEFAULT NULL COMMENT '生日',
  `sex` char(1) DEFAULT NULL COMMENT '性别',
  `address` varchar(256) DEFAULT NULL COMMENT '地址',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8;
  1. log4j配置文件(log4j.properties)
# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE            debug   info   warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE

# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE

# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:\axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
  1. mybaits主配置文件(SqlSessionFactory.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>
<!--    配置环境-->
    <environments default="mysql">
<!--        配置MySQL的环境-->
        <environment id="mysql">
<!--            配置事务类型-->
            <transactionManager type="JDBC"></transactionManager>
<!--            配置连接池-->
            <dataSource type="POOLED">
                <!--            配置数据库的基本信息-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource
        </environment>
    </environments>
<!--    指定映射配置文件-->
    <mappers>
        <mapper resource="com/itzpx/dao/IUserDao.xml"/>
    </mappers>
</configuration>
  1. dao(mapper)的映射文件IUserDao.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.itzpx.dao.IUserDao">
<!--    配置查询所有-->
    <select id="findAll" resultType="com.itzpx.domain.User">
        select * from user
    </select>
</mapper>
  1. dao(mapper)IUserDao.java
public interface IUserDao {
    //查询所有
    List<User> findAll();
}
  1. 实体类domain
public class User {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;

注意:

  1. log4j.properties、SqlMapConfig.xml文件放在resource目录下
  2. IUserDao.java文件必须与IUserDao.xml文件目录名相同

2.2 有了以上环境就可以实现入门案例

@Test
    public void TestFindAll() throws Exception {
        //1.读取配置文件
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建SqlSessionFactory工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(is);
        //3.使用工厂生成SQLSession对象
        SqlSession sqlSession = factory.openSession();
        //4.使用SqlSession创建Dao接口的代理对象
        IUserDao dao = sqlSession.getMapper(IUserDao.class);
        //5.使用代理对象执行方法
        List<User> all = dao.findAll();
        for (User user : all) {
            System.out.println(user);
        }
        //6.释放资源
        sqlSession.close();
        is.close();
    }

2.3 通过入门案例简单分析里面的对象

  1. SqlSessionFactory (SqlSession工厂对象)
    功能:
    一,加载SqlMapConfig.xml配置文件,连接数据库
    二,读取SqlMapConfig.xml配置文件下配置的映射文件信息
    三,生产Session
    方法:
    一,openSession();产生session对象
  2. SqlSession (数据库操作对象)
    功能:
    一,产生动态代理对象(该对象取代实现类)
    二,执行sql查询
    方法:
    一,getMapper(Class);产生动态代理对象
    二,**commit();**提交事务
    三,里面定义了增删改查的所有方法来执行sql语句
  3. SqlSessionFactoryBuilder 创建工厂的对象
    功能:
    一,创建SqlSessionFactory 对象,SqlSessionFactory 是个接口,无法new
    方法:
    一,build(InputStream);加载配置文件,创建工厂对象

3. mybaits的crud

3.1 简单的crud

一. 添加User

<!--    添加User-->
    <insert id="saveUser" parameterType="com.itzpx.domain.User">
        <selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
            select last_insert_id();
        </selectKey>
        insert into user (username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address});
    </insert>

其中

  1. id=“saveUser” 表示IUserDao中定义的添加方法名字为saveUser
  2. parameterType="com.itzpx.domain.User"表示传递的参数类型为User对象
  3. selectKey标签为获取插入后的id
  4. keyProperty实体类的id
  5. keyColumn表中的id
  6. resultType返回值类型
  7. #{username}代表获取传递过来的User对象中的username属性值,如果属性值与该属性的getUsername方法的Username不同,以Username为准。

二、删除User

<!--    删除User-->
    <delete id="deletUser" parameterType="Integer">
        delete from user where id = #{id}
    </delete>

三、修改User

<!--    修改User-->
    <update id="updateUser" parameterType="com.itzpx.domain.User">
        update user set username = #{username},birthday = #{birthday},sex = #{sex},address = #{address} where id = #{id}
    </update>

四、查询

<!--    根据用户名查询-->
    <select id="findUserbyUserName" parameterType="String" resultType="com.itzpx.domain.User">
        select * from user where username = #{username}
    </select>

五、模糊查询两种方式给%%
第一种方式在调用方法的时候需要传递%参数%
也就是List users = dao.findUserByUsernameLike("%王%");

<!--    模糊查询-->
    <select id="findUserByUsernameLike" parameterType="String" resultType="com.itzpx.domain.User">
        select * from user where username like #{username}
    </select>

第二种方式使用’%${value}%'的书写格式给百分号

	<select id="findUserByUsernameLike2" parameterType="String" resultType="com.itzpx.domain.User">
        select * from user where username like '%${value}%'
    </select>

注意${value}中的value是固定的,不能修改
第一种方式sql语句参数的赋值为占位符方式,也就是%?%,用paramters去赋值
第二种方式sql语句参数为拼接字符串的方式,也就是%王%

提问,为什么可以使用属性直接获取值呢?

  1. mybaits使用了OGNL表达式,对象图导航语言,也就是省略了user.getXXX()。
    直接使用user.XXX的方式,而在parpameterType中已经提供了user,所以在取值的时候,可以直接使用XXX。
    XXX代表属性名称,getXXX().

3.2 深入复杂的crud

一、条件类型的封装
将多个对象封装为一个对象作为查询条件进行查询

public class QueryVo {
    public User getUser() {
        return user;
    }
<!--    条件类型的封装-->
    <select id="findUserByQueryVo" parameterType="com.itzpx.domain.QueryVo" resultType="com.itzpx.domain.User">
        select * from user where username like #{user.userName}
    </select>

注意:在开发过程中,可能需要将一个或多个对象,封装为一个对象进行查询,所以在取值的时候需要用点来获取对象中的属性值
二、当数据库列名与实体类中的属性名不一致,怎么办?
解决方法:

  1. 查询语句取别名
<select id="findAll" resultType="com.itzpx.domain.User">
        select id as userId,username as userName,birthday as userBirthday,sex as userSex,address as userAddress from user 
</select>
  1. resultMap方式
    <resultMap id="userMap" type="com.itzpx.domain.User">
        <id property="userId" column="id"/>
        <result property="userName" column="username"/>
        <result property="userBirthday" column="birthday"/>
        <result property="userSex" column="sex"/>
        <result property="userAddress" column="address"/>
    </resultMap>
<!--    配置查询所有-->
    <select id="findAll" resultMap="userMap">
        select * from user
    </select>

注意:resultMap=“userMap”

4. properties标签的使用

第一种

	<properties>
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql:///mybatis?characterEncoding=utf8"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </properties>
<!--    配置环境-->
    <environments default="mysql">
<!--        配置MySQL的环境-->
        <environment id="mysql">
<!--            配置事务类型-->
            <transactionManager type="JDBC"></transactionManager>
<!--            配置连接池-->
            <dataSource type="POOLED">
                <!--            配置数据库的基本信息-->
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

第二种、将配置信息定义到jdbcConfig.properties文件中

<properties resource="jdbcConfig.properties">
    </properties>
<!--    配置环境-->
    <environments default="mysql">
<!--        配置MySQL的环境-->
        <environment id="mysql">
<!--            配置事务类型-->
            <transactionManager type="JDBC"></transactionManager>
<!--            配置连接池-->
            <dataSource type="POOLED">
                <!--            配置数据库的基本信息-->
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

注意:里面还有个属性是url,是统一资源定位符
写法为:协议,主机名,端口号,uri
支持http协议
也支持file协议

5. typeAliases标签的使用

主配置文件下的标签
主要功能,给domain下的实体类其别名

<typeAliases>
       <typeAlias type="com.itzpx.domain.User" alias="user"></typeAlias>
</typeAliases>

起完别名后不再区分大小写
也就是说在mapper.xml文件中就就不用写全限定类名了,直接写别名
当然,一个一个的起别名,很麻烦,不如一起起别名

<typeAliases>
<!--        <typeAlias type="com.itzpx.domain.User" alias="user"></typeAlias>-->
        <package name="com.itzpx.domain"/>
    </typeAliases>

这种方式以domain包下面的实体类,类名为别名
package标签还有一种使用

<!--    指定映射配置文件-->
    <mappers>
<!--        <mapper resource="com/itzpx/dao/IUserDao.xml"/>-->
<!--        <mapper class="com.itzpx.dao.IUserDao"/>-->
        <package name="com.itzpx.dao"/>
    </mappers>

在指定加载映射配置文件的时候,一个一个加太麻烦,一股脑的加
注意:不管是mapper.xml方式,还是注解方式都不用写了,也就是不用写resource,和class

6. 连接池

6.1 连接池的使用

mybatis连接池提供了3种方式的配置
配置的位置:
主配置文件SqlMapConfig.xml中的dataSource标签,type属性就是表示采用何种连接池方式。
type属性的取值:
POOLED 采用传统的javax.sql.DataSource规范中的连接池,mybatis中有针对规范的实现
UNPOOLED 采用传统的获取连接的方式,虽然也实现Javax.sql.DataSource接口,但是并没有使用池的思想。
JNDI 采用服务器提供的JNDI技术实现,来获取DataSource对象,不同的服务器所能拿到DataSource是不一样。
注意:如果不是web或者maven的war工程,是不能使用的。
我们使用的是tomcat服务器,采用连接池就是dbcp连接池。

6.2 连接池分析

UNPOOLED:
在mybatis中的实现类是UnpooledDataSource
其通过分析getConnection()方法可以看出
其获取Connection的方式是直接加载驱动,获取连接后返回连接
由此可以看出其并未使用连接池
POOLED
在mybatis中的实现类是PooledDataSource
getConnection()方法调用了popConnection()
步骤

  1. while(conn == null) {//如果没有连接
  2. synchronized(this.state) {//同步代码块,说明连接池必须是线程安全的
  3. if (!this.state.idleConnections.isEmpty()) {//如果没有空闲的连接
  4. idleConnections代表的就是一个ArrayList集合

按照此步骤推理下去
POOLED是使用了自定义的连接池技术
在PooledDataSource类中定义了连接池的默认属性,这些属性可以在主配置文件中修改

protected int poolMaximumActiveConnections = 10;
protected int poolMaximumIdleConnections = 5;
protected int poolMaximumCheckoutTime = 20000;
protected int poolTimeToWait = 20000;
protected int poolMaximumLocalBadConnectionTolerance = 3;

7. 事务

7.1 事务的使用

主要是通过两个方法
commit();
rollback();

7.2 事务分析

mybaits中事务是默认不提交的
需要手动提交事务
也可以设置为自动提交事务
在factory.openSession(true);
创建sqlsession的时候

8. 动态sql语句

8.1 if

判断是否由条件

<select id="findUserByEv" parameterType="user" resultMap="userMap">
        select * from user where 1 = 1
        <if test="userName != null">
            and username = #{userName}
        </if>
        <if test="userBirthday != null">
            and birthday = #{userBirthday}
        </if>
    </select>

注意:其中不能使用&& || 的符号,只能用and or作为条件连接

8.2 where

where主要是去除where 1 = 1这一端,他会根据是否由条件进行拼接字符串

<select id="findUserByEv" parameterType="user" resultMap="userMap">
        select * from user
        <where>
            <if test="userName != null">
                and username = #{userName}
            </if>
            <if test="userSex != null">
                and sex = #{userSex}
            </if>
        </where>
    </select>

8.3 foreach

主要是对集合的遍历

<!--    查询条件中有集合,如何去遍历集合-->
    <select id="findUserOnIds" parameterType="com.itzpx.domain.QueryVo" resultMap="userMap">
        select * from user
        <where>
            <if test="ids != null and ids.size()>0">
                <foreach collection="ids" open="and id in(" close=")" separator="," item="uid">
                    #{uid}
                </foreach>
            </if>
        </where>
    </select>

其中collection=“ids”//表示需要被遍历的集合
open=“and id in(”//表示拼接的开始
close=")"//表示拼接的结束
separator=","//表示分割的符号
item=“uid”//表示从集合中遍历出来的数据
#{uid}//代表取出数据
结果是
select * from user WHERE id in( ? , ? , ? )
提问:为什么要加and id in(
可能是如果where后面如果有条件的话
select * from user WHERE 其他条件 and id in( ? , ? , ? )
如果没有其他条件,mybaits会把and去掉

8.4 sql标签

公共代码片段的抽取

	<sql id="selectId">
        select * from user
    </sql>
    <include refid="selectId"/>

9. 多表操作

9.1 一对多

描述:一个用户,有多个账户
在查询多表时
select * from user,account
这样的语句返回的结果集,关系到多个实体类,所以需要定义
resultMap,来封装结果集
注意:在user实体类中定义account的集合,set\get

<resultMap id="userAccountMap" type="user">
<!--        定义user表字段的封装-->
        <id property="id" column="id"/>
        <result property="userName" column="username"/>
        <result property="birthday" column="birthday"/>
        <result property="sex" column="sex"/>
        <result property="address" column="address"/>
<!--        定义user表关联的account表的数据封装-->
        <collection property="accounts" column="uid" ofType="account">
            <id property="id" column="aid"/>
            <result property="uid" column="uid"/>
            <result property="money" column="money"/>
        </collection>
    </resultMap>
<!--    配置查询所有-->
    <select id="findAll" resultMap="userAccountMap">
        SELECT
            *
        FROM
	        user AS u
        LEFT JOIN
	        account AS a
        ON
            u.id = a.uid
    </select>

9.2 一对一

描述:一对一其实是多对一,在mybaits中认为一个账户只能对应一个用户,这就是一对一,其实多个账户能对应一个用户,但在mybaits中没有这种说法,所以统一为一对一
查询所有账户的用户信息

<resultMap id="accountUserMap" type="account">
        <id property="id" column="aid"></id>
        <result property="uid" column="uid"></result>
        <result property="money" column="money"></result>
        <!--和一对多不同,使用的是association 标签-->
        <association property="user" column="uid"  javaType="user">
            <id property="id" column="id"></id>
            <result column="username" property="userName"></result>
            <result property="birthday" column="birthday"></result>
            <result property="sex" column="sex"></result>
            <result property="address" column="address"></result>
        </association>
    </resultMap>
<!--    配置查询所有账户的用户信息-->
    <select id="findAll" resultMap="accountUserMap">
        SELECT
            u.*,a.id as aid,a.uid,a.money
        FROM
            account as a,
            user as u
        WHERE
            u.id = a.uid
    </select>

注意:account实体类中,有user对象定义 get/set

9.3 多对多

描述:一个用户可以拥有多个角色,一个角色赋予多个用户,
这种表关系就需要中间表进行连接,中间表主要字段uid,rid,
多对多,写法和一对多写法类似
1.查询用户所拥有的角色信息

<resultMap id="userMap" type="user">
    <id property="id" column="id"></id>
    <result property="userName" column="username"/>
    <result property="birthday" column="birthday"/>
    <result property="sex" column="sex"/>
    <result property="address" column="address"/>
    <collection property="roles" column="rid" ofType="role">
        <id property="roleId" column="rid"/>
        <result property="roleName" column="ROLE_NAME"/>
        <result property="roleDesc" column="ROLE_DESC"/>
    </collection>
</resultMap>

<!--    配置查询所有-->
    <select id="findAll" resultMap="userMap">
        SELECT
            u.*,r.id AS rid,r.ROLE_NAME,r.ROLE_DESC
        FROM
	        user AS u
	    LEFT JOIN
	        user_role AS ur
	    ON
	        u.id=ur.uid
	    LEFT JOIN
	        role AS r
	    ON
	        r.id=ur.rid
    </select>

2.反过来查询角色赋予的用户信息

<resultMap id="roleMap" type="role">
    <id property="roleId" column="id"></id>
    <result property="roleName" column="ROLE_NAME"></result>
    <result property="roleDesc" column="ROLE_DESC"></result>
    <collection property="users" column="uid" ofType="user">
        <id property="id" column="id"></id>
        <result property="userName" column="username"></result>
        <result property="birthday" column="birthday"></result>
        <result property="sex" column="sex"></result>
        <result property="address" column="address"></result>
    </collection>
</resultMap>

<!--    配置查询所有-->
    <select id="findAll" resultMap="roleMap">
        SELECT
            r.*,u.id AS uid,u.username,u.birthday,u.sex,u.address
        FROM
	        role r
	    LEFT JOIN
	        user_role ur
	    ON
	        r.id=ur.rid
	    LEFT JOIN
	        user u
	    ON
	        u.id = ur.uid
    </select>

注意:user实体类中有role集合,role实体类中有user集合

10. 延迟加载

10.1 一对一的延迟加载

查询用户信息时,用户所关联的账户信息在需要的时候加载。
这就是延迟加载
需要在主配置文件中开启延迟加载

<!--    配置开启延迟加载-->
    <settings>
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

查询所有账户

<resultMap id="accountUserMap" type="account">
        <id property="id" column="id"></id>
        <result property="uid" column="uid"></result>
        <result property="money" column="money"></result>
        <association property="user" column="uid"  javaType="user" select="com.itzpx.dao.IUserDao.findAllById"></association>
    </resultMap>
<!--    配置查询所有账户的用户信息-->
    <select id="findAll" resultMap="accountUserMap">
        SELECT
            *
        FROM
            account
    </select>

select=“com.itzpx.dao.IUserDao.findAllById”
表示的时,调用findAllById方法,根据column="uid"去查询account表
该方法在com.itzpx.dao.IUserDao中

<!--    根据id查询-->
    <select id="findAllById" resultType="user" parameterType="int">
        SELECT
            *
        FROM
            user u
        WHERE
            u.id = #{uid}
    </select>

当查询出来的account列表被使用到的时候,就会调用findAllById,查出用户信息

10.2 一对多的延迟加载

查询user表,

<resultMap id="userAccountMap" type="user">
        <id property="id" column="id"/>
        <result property="userName" column="username"/>
        <result property="birthday" column="birthday"/>
        <result property="sex" column="sex"/>
        <result property="address" column="address"/>
        <collection property="accounts" column="id" ofType="account" select="com.itzpx.dao.IAccountDao.findAccountById"></collection>
    </resultMap>

<!--    配置查询所有-->
    <select id="findAll" resultMap="userAccountMap">
        SELECT
            *
        FROM
	        user
    </select>
<select id="findAccountById" resultType="account" parameterType="int">
        select * from account where uid = #{uid}
    </select>

11. 缓存

11.1 一级缓存

一、如何使用一级缓存
一级缓存,与sqlSession相关,当重复调用查询方法时,且参数相同,就会到sqlSession中查询一级缓存

User user1 = userDao.findUserById(45);
system.out.prinl(user1);
User user2 = userDao.findUserById(45);
system.out.prinl(user2);
system.out.prinl(user1 == user2);

此时,user1与user2为同一个对象,地址都一样,比较结果为true
二、如何关闭一级缓存
一级缓存关闭,或消失

  1. sqlSession对象消失
  2. sqlSession.clearCache();调用该方法,清空一级缓存
  3. 执行update、insert、delete、commit、等方法

11.2 二级缓存

一、二级缓存的描述
该缓存,由sqlSessionFactory提供,同一个sqlSessionFactory,创建的所有sqlSession共享其缓存。
二、如何开启二级缓存
三步

  1. sqlMapConfig配置文件中开启二级缓存
	<settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>
  1. Mapper配置文件中开启二级缓存
	<cache/>
  1. select标签中开启二级缓存,useCache=“true”
<select id="findAll" .... useCache="true">

三、验证二级缓存
在同一个sqlSessionFactory下创建的不同sqlSession,执行同一个方法,比如说执行findAll();
结果:mybaits,只查询一次,其他相同查询都在缓存中拿数据

12. 注解开发

12.1 环境搭建

12.2 单表crud

	//查询所有
    @Select(value="select * from user")
    @Results(id="userMap",value={
            @Result(id=true,column = "id",property = "userId"),
            @Result(column = "username",property = "userName"),
            @Result(column = "birthday",property = "userBirthday"),
            @Result(column = "sex",property = "userSex"),
            @Result(column = "address",property = "userAddress")
    })
    List<User> findAll();
    //根据ID查询用户
    @Select("select * from user where id = #{id}")
    @ResultMap(value="userMap")
    User findUserById(Integer id);
    //根据ID修改用户
    @Update(value="update user set username = #{userName}," +
            "birthday = #{userBirthday}," +
            "sex = #{userSex}," +
            "address = #{userAddress} " +
            "where id = #{userId}")
    void updateUser(User user);
    //添加一条数据
    @Insert("insert into user (id,username,birthday,sex,address) values (null,#{userName},#{userBirthday},#{userSex},#{userAddress})")
    Integer interUser(User user);

12.3 多表查询

一对一

//查询账户信息,与账户相关的用户信息
    @Select("select * from account")
    @Results(id="accountMap",value={
            @Result(id=true,column="id",property="accountId"),
            @Result(column="uid",property="accountUid"),
            @Result(column="money",property="accountMoney"),
            @Result(one = @One(select = "com.itzpx.dao.IUserDao.findUserById"),column = "uid",property = "user")
    })
    List<Account> findAll();
    //根据uid查询account
    @Select("select * from account where uid = #{uid}")
    @ResultMap(value="accountMap")
    Account findAccountByUid(Integer uid);
//查询所有
    @Select(value="select * from user")
    @Results(id="userMap",value={
            @Result(id=true,column = "id",property = "userId"),
            @Result(column = "username",property = "userName"),
            @Result(column = "birthday",property = "userBirthday"),
            @Result(column = "sex",property = "userSex"),
            @Result(column = "address",property = "userAddress")
    })
    List<User> findAll();
    //根据ID查询用户
    @Select("select * from user where id = #{id}")
    @ResultMap(value="userMap")
    User findUserById(Integer id);

一对多

//查询用户,及关联的账户
    @Select("select * from user")
    @Results(id="userAccountMap",value={
            @Result(id=true,column = "id",property = "userId"),
            @Result(column = "username",property = "userName"),
            @Result(column = "birthday",property = "userBirthday"),
            @Result(column = "sex",property = "userSex"),
            @Result(column = "address",property = "userAddress"),
            @Result(many = @Many(select = "com.itzpx.dao.IAccountDao.findAccountByUid"),column = "id",property = "accounts")
    })
    List<User> findUserAndAccount();
//查询账户信息,与账户相关的用户信息
    @Select("select * from account")
    @Results(id="accountMap",value={
            @Result(id=true,column="id",property="accountId"),
            @Result(column="uid",property="accountUid"),
            @Result(column="money",property="accountMoney"),
            @Result(one = @One(select = "com.itzpx.dao.IUserDao.findUserById"),column = "uid",property = "user")
    })
    List<Account> findAll();
    //根据uid查询account
    @Select("select * from account where uid = #{uid}")
    @ResultMap(value="accountMap")
    Account findAccountByUid(Integer uid);

多对多
注意:多对多在sql中需要使用一些技巧,不能使用left join一路连接过去,应该
这样写:id(column = “id”)传递过去,然后根据id查询
@Select(“select * from user where id in (select uid from user_role where rid = #{id})”)

//查询所有
    @Select("select * from role")
    @Results(id="roleMap",value={
            @Result(id=true,column = "id",property="roleId"),
            @Result(column = "ROLE_NAME",property="roleName"),
            @Result(column = "ROLE_DESC",property="roleDesc"),
            @Result(many = @Many(select = "com.itzpx.dao.IUserDao.findUserById2"),column = "id",property = "users")
    })
    List<Role> findAll();
//根据ID查询用户
    @Select("select * from user where id in (select uid from user_role where rid = #{id})")
    @ResultMap(value="userMap")
    List<User> findUserById2(Integer id);

12.4 缓存配置

在dao接口上添加
@CacheNamespace(blocking = true)

13 mybaits留下的知识点

  1. 自定义mybaits
  2. JDNI数据源(基本使用已了解)
WINDOWS下SIP拨号的实现 在WIN10上拨打SIP电话  由于我的交换原理实验有一个是关于SIP的抓包的。而之前从未接触过SIP,所以在如何完成一次SIP拨号上遇到了不少问题,查了好多资料都没有完整的或者写的很清楚的,这里就对那些资料做一个总结,给出一个比较完善的解决方案,一来是记录此次实验的收获,而来也可能为其他有同样困惑的人解惑。  废话不多说直接开始。首先是下载一个可以拨打SIP电话的客户终端,这里我选择的是MicroSIP, 下载红圈内的文件,下载好之后直接一路安装即可,没有什么特别注意的地方。  安装好客户端之后,就需要注 阅读详情

相关推荐

YOLOv11多模态融合实战:基于YOLOFuse的RGB与红外线(IR)协同检测技术解析

本文深入解析了YOLOv11多模态融合技术,重点介绍基于YOLOFuse框架的RGB与红外线(IR)协同检测方法。通过动态权重分配、跨模态特征对齐等创新设计,实现在低光照等复杂环境下的高精度目标检测,mAP提升高达37%。文章包含实战案例、训练技巧和部署方案,为计算机视觉开发者提供完整的多模态融合解决方案。

weixin_29038345的博客 292

mybatis基于xml和注解查询

一. Mybatis介绍 1.mybatis基础环境搭建 1. 创建数据库 SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for t_emp -- ---------------------------- DROP TABLE IF EXISTS `t_emp`; CREATE TABLE `t_emp` ( `emp_id` int(11) NOT NULL AUTO_INCREMENT,

pscool的博客 1911

图像质量评估(5) -- 畸变(Distortion)

当图像中原本应该是直线的地方看起来发生了不自然的变形或扭曲时,我们称为图像畸变。有三种类型的镜头畸变:桶形畸变(后文使用英文barrel),枕形畸变(后文使用pincushion)和胡子畸变(后文使用英文wavef或mustache,这种畸变里包含了桶形畸变和枕形畸变)。有一个重要的点需要注意,根据透镜的类型以及透镜是否能够从相机中移除等条件不同,畸变会有不同的表现。 总的来说,旋转对称光学系统功能上会产生和物体几何相似的图形。但也有少数特殊的系统是例外,例如鱼眼镜头,这种镜头几何是故意设计为

vivo01的专栏 2万+

Mybatis-Plus学习小项目及详细教程

Mybatis-Plus学习总结 Mybatis-plus官网:https://baomidou.com/ Mybatis-plus详细教程:https://www.hxstrive.com/subject/mybatis_plus.htm Mybatis-plus简介 MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。 Mybatis-p

专注Java后端技术干货、项目源码总结分享,期待您的关注。 719

避坑指南:Ubuntu 22.04上源码编译Autoware.universe(Humble版)的完整流程与常见错误修复

本文详细介绍了在Ubuntu 22.04上源码编译Autoware.universe(Humble版)的完整流程与常见错误修复方法。从环境准备、依赖安装到编译优化,提供了实用的避坑指南和解决方案,帮助开发者高效完成安装并避免常见问题。特别针对源码安装过程中的疑难杂症给出了具体修复建议。

weixin_33712987的博客 383

具身智能中的运动控制如何入门?

本文提出计算机视觉(CV)与强化学习(RL)结合的机器人运动控制学习路径。强调工程实践导向,建议采用"算法-机器人-工程"三阶段学习法:基础阶段掌握RL核心算法(PPO/SAC)和机器人动力学;进阶阶段聚焦Sim2Real技术(域随机化、模仿学习)和仿真环境搭建;深耕阶段结合CV优势开发视觉闭环控制等创新方向。特别指出应避免纯理论学习,提倡"最小知识原则"的实践模式,通过具体项目(如四足机器人控制)串联知识体系。推荐以《现代机器人学》等工具书为参考,配合开源框架(Pi

CyberSoma的博客 321

MyBatis系列--与Spring整合

整合环境搭建 1.创建一个Maven项目 在pom.xml导入所需要的jar包坐标 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 htt

qq_43404873的博客 351

精度与速度双突破:YOLOv8-Pose 在 RK3588 上实现高性能人体姿态分析部署

本教程从YOLOv8-pose模型的姿态识别训练,到RK3588的边缘量化部署,为你打造了一套“高精度+高实时性+低成本”的人体姿态分析解决方案。无论是健身动作纠正、智能安防行为检测,还是工业人员姿态监控,这套技术都能直接复用——你只需替换数据集与业务逻辑,即可快速落地专属的边缘AI姿态识别系统。如果你在实践中遇到任何卡点,欢迎随时交流。记住,人体姿态识别的价值在于“关键点准、推理快、部署易”,而这三者的平衡,正是你通过本教程能掌握的核心能力。

know_F0727的博客 435

MySQL启动和关闭外键约束的方法(FOREIGN_KEY_CHECKS)

在MySQL中删除一张表或一条数据的时候,出现[Err] 1451 -Cannot delete or update a parent row: a foreign key constraint fails (...)这是因为MySQL中设置了foreign key关联,造成无法更新或删除数据。可以通过设置FOREIGN_KEY_CHECKS变量来避免这种情况。SET FOREIGN_KEY_CH...

9t night的博客 829

Pyinstaller打包为可执行文件编码错误的问题

Pyinstaller打包为可执行文件编码错误的问题 写好的python程序在vscode上运行没有任何问题,将程序利用pyinstaller打包后,运行程序发生了错误。 错误代码 UnicodeDecodeError: ‘utf-8' codec can't decode byte 0xce in position 20-21:invalid cotinuation byte 网上找到的解决方案是: 1.在命令行中输入 chcp 65001 2.按正常方式进行封装 pyinstaller

xuefeng_he的博客 1560

pytorch 51 GroundingDINO模型导出tensorrt并使用c++进行部署,53ms一张图

博主基于https://github.com/hpc203/GroundingDINO-onnxrun项目分享的onnx c++推理代码,修改为GroundingDINO模型的tensorrt推理代码。对于600x400的输入,在3060显卡下,cuda 12.1,TensorRT-10.4.0,window环境下53ms处理完一张图片。

a486259的博客 1221

[MySql]MySql中外键设置 以及Java/MyBatis程序对存在外键关联无法删除的规避

在MySql设定两张表,其中product表的主键设定成orderTb表的外键,具体如下: 产品表: create table product(id INT(11) PRIMARY KEY,name VARCHAR(32) ); 订单表: create table orderTb(id INT(11) PRIMARY KEY,productid INT(11), FOREIGN...

weixin_30813225的博客 675

如何使用Agent框架来模拟群体智能?

Agent 框架作为人工智能领域的重要工具,可以模拟复杂的群体智能行为,广泛应用于社会科学、经济学和行为学等领域。

335

阶段四:Mybatis框架

一、Mybatis简介 Mybatis是一款优秀的开源的持久层框架,支持自定义SQL语句,存储过程以及高级映射。 Mybatis封装了大量的JDBC代码,简化了设置参数以及结果集映射等操作,只需要使用者做简单的配置并遵守配置的规则即可。 1.1 Mybatis历史 Mybatis的前身是apache的开源项目iBatis,在2010年被谷歌收购并改名为Mybatis,2013年迁移到github上。 1.2 优点 1、简单,易上手。没有第三方依赖 2、解除了java程...

Xiong_M_DD的博客 323

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

手写MyBatis第40弹:手写MyBatis框架阶段性总结,你的ORM框架已达生产级雏形

本文回顾了手写MyBatis框架的实现过程,总结了当前框架具备的CRUD功能和两种操作方式:优雅的Mapper代理接口与灵活的SqlSession API。文章详细解析了核心组件(如SqlSessionFactory、Executor等)的职责与协作机制,并展望了未来扩展方向,包括插件机制、缓存优化、事务管理等,旨在打造更强大的生产级ORM框架。通过这一实践,读者不仅能深入理解MyBatis架构,还能掌握Java高级编程技术的综合运用。

源码获取 | 运行部署 | 定制二开修改,如果回复不及时请耐心等待,请见谅。 733

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

阶段四:热门框架(第五章:Mybatis-Plus)

MyBatisPlus环境搭建的步骤?BaseMapper通过入门案例制作,MyBatisPlus的优点有哪些?MyBatisPlus(简称MP)是基于MyBatis框架基础上开发的增强型工具,旨在简化开发、提高效率https和有什么简单的办法可以自动生成实体类的GET、SET方法?Lombok,一个Java类库,提供了一组注解,简化POJO实体类开发。

大小曲奇的博客 460

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

第六章 手写MyBatis实现笔记

一、思路分析 手写mybatis核心还是参考源码的设计,我们也从MyBatis核心流程三大阶段一步步开始实现。 1、配置文件解析 读取XML配置文件和注解中的配置信息,创建配置对象,并完成各个模块的初始化的工作,读取XML配置文件和数据库配置文件中的信息加载到configuration对象中。 1、SqlSession说明: Sqlsession意味着创建数据库会话,...

hankin的博客 306

第三阶段:Web前端:03(2)Mybatis框架 | 后端MVC设计模式 | 酷鲨商城广告页引流平台

1、Vue CLI:Vue脚手架 01.vue CLI基础: 关于Vue CLI Vue.js(读音:/vjuː/, 类似于:view)是一套构建用户界面的渐进式框架 ● Vue.js的官方网址是:https://cn.vuejs.org/index.html 需要注意:在使用传统模式开发的前端工程中,各个页面是相对独立的, 甚至你可以在本地硬盘上找到对应的html文件并双击直接打开它, 【而Vue CLI工程与一个Web应用程序一样,是需要启动服务才可以访问.

weixin_59404863的博客 400

Mybatis源码研究2:框架整体设计

本文转载自:http://chenjc-it.iteye.com/blog/1460990 1.引言 本文主要讲解Mybatis的整体程序设计,理清楚框架的主要脉络。后面文章我们再详细讲解各个组件。 2.整体设计 2.1 总体流程 (1)加载配置并初始化 触发条件:加载配置文件...

chulilang8944的博客 101

MyBatis,MyBatis-plus,Struts,Struts2,Hibernate这些技术都是什么时候出现的?

相比于Struts,Struts 2在架构上进行了改进,引入了拦截器(Interceptor)等概念,提供了更强大的功能和灵活性,是目前较为流行的Web应用开发框架之一。它通过将Web应用程序的请求处理流程分解为不同的组件,如Action和Form等,帮助开发者构建可维护和可扩展的Web应用程序。它简化了Java应用程序与关系型数据库之间的数据持久化操作,通过将Java对象与数据库表进行映射,可以避免手动编写SQL语句,并提供了高度的可移植性和扩展性。出现时间:2002年。出现时间:2016年。

weixin_46125941的博客 698

MyBatis-Plus SQL自动填充字段

在企业级开发中,维护数据的审计字段(creatorupdater)是必不可少的环节。MyBatis-Plus (MP) 提供了接口来实现这一逻辑的自动化。然而,很多开发者对这一机制存在误解,认为只要实现了 Handler 接口,填充逻辑就会自动生效。事实上,MP 内部存在一套严格的**“短路”触发机制**。本文将深入剖析这套机制的运行原理,并对比“强制赋值”与“标准填充”的区别,给出生产环境下的最佳实践代码。

czlczl20020925的博客 668

MyBatis初始化流程解析:从配置文件到SqlSessionFactory的构建

在Java持久层框架中,MyBatis以其灵活的SQL映射和简洁的配置而广受欢迎。其核心原理在于通过解析XML配置文件构建内部数据结构,最终生成可执行SQL的会话工厂。这一初始化过程涉及配置文件的加载、解析与对象化,是理解MyBatis运行机制的基础。从技术价值看,这不仅实现了SQL与Java代码的解耦,还通过动态SQL支持提升了开发效率。在实际应用场景中,无论是传统的XML配置还是现代的注解方式,都需要经过初始化流程将Mapper接口与SQL语句关联。本文以MyBatis的初始化流程为主题,深入探讨了XM

weixin_30432579的博客 488

MyBatis Flex与MyBatis Plus核心特性对比与选型指南

在Java持久层框架领域,MyBatis因其灵活性和易用性广受欢迎。作为其增强工具,MyBatis Plus和MyBatis Flex通过不同的设计理念提升开发效率。动态SQL生成是ORM框架的核心技术,MyBatis Plus采用Wrapper体系构建条件,而MyBatis Flex使用链式API,两者在Lambda支持和条件组合灵活性上各有优势。多租户和乐观锁等企业级功能实现方式也体现了框架设计差异。对于需要快速开发标准CRUD的中型项目,成熟稳定的MyBatis Plus是不错选择;而追求轻量级架构和

weixin_33552698的博客 175

java开发学习阶段

集合源码:HashMap、ConcurrentHashMap、ArrayList、LinkedList。- 锁:synchronized、ReentrantLock、volatile。- 重点:死锁、线程安全、可见性、ThreadLocal。- GC:垃圾回收算法、CMS/G1/ZGC 区别。- 能解决:超卖、重复提交、高并发下数据一致性。- 能排查:简单死锁、CPU 高、内存高问题。- 重点:扩容、哈希冲突、线程安全、红黑树。- 单例、工厂、策略、模板、适配器、装饰器。

xiaoyaozizai1的博客 276

Java工程师成长路线:从基础到框架的完整指南

Java作为企业级开发的主流语言,其生态体系庞大且成熟。理解Java语言基础、面向对象编程和高级特性是成为合格工程师的第一步。从JVM内存模型到并发编程,这些核心原理支撑着现代Java应用的开发。在实际工程中,掌握Spring框架、数据库优化和Web开发技术栈至关重要。本文提供了一条清晰的成长路径,涵盖Java基础、数据库开发、Web技术、主流框架等关键阶段,帮助开发者系统性地提升技能。特别适合正在学习Java或准备面试的工程师参考,其中包含ConcurrentHashMap并发原理、SpringBoot自

weixin_29229055的博客 244

MyBatis框架阶段总结

List itemdsd夫

长舒的博客 488
上一篇: 第22天,综合案例
下一篇: 前端知识点补充(ajax、json)
RestartJava
博客等级 码龄7年 1粉丝 53原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值