【Java】JDBC 数据库连接 (JDK17+MySQL8)

文章目录

  • JDBC 是什么?
  • 导入JDBC jar包
  • 一、JDBC的核心API和使用路线
  • 二、基于 statement 演示 查询
  • 三、基于 statement 查询的改进与问题
  • 四、基于 preparedStatement 方式优化
  • 五、基于 preparedStatement 演示 CRUD
    • C 、增加数据
    • R、查询数据
    • U、修改/更新 数据
    • D、删除数据
  • 六、preparedStatement 使用方式总结
  • 七、JDBC 扩展
    • 7.1 自增长主键回显实现
    • 7.2 批量数据插入性能提升
    • 7.3 jdbc中数据库事务实现
  • 八、Druid连接池技术使用
  • 九、JDBC使用优化以及工具类封装
  • 十、基于CMS项目JDBC实战练习
  • 总结


JDBC 是什么?

Java Database Connectivity | Java 数据库连接 技术

通过 JDBC 提供的方法 可以发送字符串 类型的 SQL语句DBMS(数据库管理系统 比如 MySQL Oracle), 并且获取到语句的执行结果。
从而实现 对 数据库 数据的 CRUD ( 增删改查 )
1
JDBCJava语言的规范(接口)各个数据库厂商的实现驱动(jar) 组成
在这里插入图片描述
JDBC是一种典型的面向接口编程
2

导入JDBC jar包

mysql版本推荐驱动版本备注
mysql 5.5.x5.0.xcom.mysql.jdbc.Driver
mysql 5.7.x5.1.xcom.mysql.jdbc.Driver
msyql 8.x8.0.x建议: 8.0.25+省略时区设置com.mysql.cj.jdbc.Driver

Java工程导入依赖
1. 项目创建lib文件夹
2. 导入驱动依赖jar包
3. jar包右键-添加为项目依赖
2


一、JDBC的核心API和使用路线

JDBC 技术组成:

  1. JDK下JDBC规范接口 , 存储在 java.sql 和 javax.sql 包中的API

为了项目代码的可移植性,可维护性,SUN公司从最初就制定了Java程序连接各种数据库的统一接口规范。这样的话,不管是连接哪一种DBMS软件,Java代码可以保持一致性。

  1. 各个数据库厂商提供的驱动jar包

因为各个数据库厂商的DBMS软件各有不同,那么内部如何通过sql实现增、删、改、查等管理数据,只有这个数据库厂商自己更清楚,因此把接口规范的实现交给各个数据库厂商自己实现。

  1. jar包是什么?

java程序打包的一种压缩包格式,可以将这些jar包引入项目中,就可以使用这个java程序中类和方法以及属性了!


核心类和接口
1.2
DriverManager 获取连接;
接着建立连接;
PreparedStatement(最常用)发送sql语句;
若是查询操作,则对应的查询结果放在Result中。

  1. DriverManager
    • 将第三方数据库厂商的实现驱动jar注册到程序中
    • 可以根据数据库连接信息获取connection
  2. Connection [建立连接]
    • 和数据库建立的连接,在连接对象上,可以多次执行数据库CRUD动作
    • 可以获取 statementpreparedstatement , callablestatement对象
  3. Statement【适用静态sql路线 没有动态值的】
    PreparedStatement【预编译sql 有动态值语句】
    CallableStatement
    • 具体发送SQL语句到数据库管理软件的对象
    • 不同发送方式稍有不同! preparedstatement 使用为重点!
  4. Result【对查询语句才有】(查询的结果)
    • 面向对象思维的产物 (抽象成数据库的查询结果表)
    • 存储DQL查询数据库结果的对象
    • 需要我们进行解析,获取具体的数据库数据

API 使用路线
api

JDBC基本使用步骤分析(6步)

  1. 注册驱动【依赖的jar包 进行安装】
  2. 获取连接【connection建立连接】
  3. 创建发送sql语句对象【statement 创建发送sql语句的statement】
  4. 发送sql语句,并获取返回结果【statement发送sql语句到数据库 并且取得返回结构】
  5. 结果集解析【将result结果解析出来】
  6. 资源关闭【释放resultset、statement、connection】

二、基于 statement 演示 查询

  1. 准备数据库数据
CREATE DATABASE jdbc_test;

USE jdbc_test;

CREATE TABLE t_user(
   id INT PRIMARY KEY AUTO_INCREMENT COMMENT '用户主键',
   account VARCHAR(20) NOT NULL UNIQUE COMMENT '账号',
   PASSWORD VARCHAR(64) NOT NULL COMMENT '密码',
   nickname VARCHAR(20) NOT NULL COMMENT '昵称');
   
INSERT INTO t_user(account,PASSWORD,nickname) VALUES
  ('root','123456','经理'),('admin','666666','管理员');
  1. 代码实现
 // @Description: 使用statement查询t_user表下,全部数据
// 1. 注册驱动
        DriverManager.registerDriver(new Driver());

        // 2. 建立连接
        /*
         *       java连接数据库肯定是调用某个方法,方法也需要填入数据库的基本信息:
         *       数据库ip地址:127.0.0.1
         *       数据库端口号:3306
         *       账号:root
         *       密码:root
         *       连接数据库的名称:jdbc_test
         *
         *      DriverManager.getConnection的参数
         *      参数1 url:
         *      jdbc:数据库厂商名://ip地址:port/数据库名
         *      jdbc:mysql://127.0.0.1:3306/jdbc_test
         * */
        //java.sql 接口 = 实现类
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc_test",
                "root", "root");

        // 3. 创建statement对象
        Statement statement = connection.createStatement();

        // 4. 发送sql
        String sql = "SELECT * FROM t_user";
        ResultSet resultSet = statement.executeQuery(sql);

        // 5. 接收 解析返回的结果集
        while (resultSet.next()) {
            int id = resultSet.getInt("id");
            String account = resultSet.getString("account");
            String password = resultSet.getString("password");
            String nickname = resultSet.getString("nickname");
            //输出列的结果
            System.out.println(id + "--" + account + "--" + password + "--" + nickname);
        }
        // 6. 关闭资源【先打开的后关】
        resultSet.close();
        statement.close();
        connection.close();

result

三、基于 statement 查询的改进与问题

需求:模拟登录 输入用户名/密码

//1.输入账号和密码
        Scanner scanner = new Scanner(System.in);
        String account = scanner.nextLine();
        String password = scanner.nextLine();
        scanner.close();

        //方法1:DriverManager.registerDriver(new Driver());调用两次。不用
        //方法2:new Driver()  频繁修改不优雅
        //方法3.使用反射 注册一次驱动
        Class.forName("com.mysql.cj.jdbc.Driver");

        //获取连接
        //省略写法: jdbc:mysql://localhost:3306/test = jdbc:mysql:///test
        Connection connection = DriverManager.getConnection("jdbc:mysql:///jdbc_test", "root", "root");

        //固定方法固定剂
        //创建statement
        Statement statement = connection.createStatement();

        //执行SQL语句 [动态SQL语句,需要字符串拼接]
        String sql = "select * from t_user where account = '"+account+"' and password = '"+password+"' ;";

        /**
         *  ResultSet 结果集对象 = executeQuery(DQL语句)
         *  int响应行数  = executeUpdate(非DQL语句)
         */
        ResultSet resultSet = statement.executeQuery(sql);

        //ResultSet == navicat
        /**
         * 1.需要理解ResultSet的数据结构和navicat查询出来的是一样!
         * 2.有一个光标指向的操作数据行,默认指向第一行的上边!我们需要移动光标,指向行,在获取列即可!
         *        boolean = next()
         *              false: 没有数据,也不移动了!
         *              true:  有更多行,并且移动到下一行!
         *       推荐:推荐使用if 或者 while循环,嵌套next方法,循环和判断体内获取数据!
         *       if(next()){获取列的数据!} ||  while(next()){获取列的数据!}
         *
         *3.获取当前行列的数据!
         *        get类型(int columnIndex | String columnLabel)
         *        列名获取  //lable 如果没有别名,等于列名, 有别名label就是别名,他就是查询结果的标识!
         *        列的角标  //从左到右 从1开始! 数据库全是从1开始!
         */

        //进行结果集对象解析
        if (resultSet.next()){
            //只要向下移动,就是有数据 就是登录成功!
            System.out.println("登录成功");
        }else{
            System.out.println("登录失败");
        }

        //关闭资源
        resultSet.close();
        statement.close();
        connection.close();

存在的问题:

  1. SQL语句需要字符串拼接,比较麻烦
  2. 只能拼接字符串类型,其他的数据库类型无法处理
  3. 可能发生注入攻击

四、基于 preparedStatement 方式优化

利用preparedStatement解决上述案例注入攻击SQL语句拼接问题!

public class PreparedStatementLoginPart {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        // 1. 输入用户名 密码
        Scanner scanner = new Scanner(System.in);
        String account = scanner.nextLine();
        String password = scanner.nextLine();
        scanner.close();

        // 2. 注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");

        // 3. 获取连接
        Connection connection = DriverManager.getConnection("jdbc:mysql:///jdbc_test", "root", "root");

        // 4.创建sql对象 与 sql语句
        String sql = "SELECT * FROM t_user WHERE account = ? AND password = ?;" ;
        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        // 占位符? 赋值  从左到右,从1开始
        // 参数:int 占位符下角标 ; objects 占位符的值
        preparedStatement.setObject(1,account);
        preparedStatement.setObject(2,password);

        // 5. 结果集解析
        ResultSet resultSet = preparedStatement.executeQuery();
        if (resultSet.next()) {
            //只要向下移动,就是有数据 就是登录成功!
            System.out.println("登录成功");
        }else{
            System.out.println("登录失败");
        }

        resultSet.close();
        preparedStatement.close();
        connection.close();
    }
}

五、基于 preparedStatement 演示 CRUD

C 、增加数据

       /**
     * 插入一条用户数据!
     * 账号: test
     * 密码: test
     * 昵称: 测试
     */
    @Test
    public void testInsert() throws SQLException, ClassNotFoundException {
        Class.forName("com.mysql.cj.jdbc.Driver");

        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/jdbc_test", "root", "root");

        String sql = "INSERT INTO t_user(account,password,nickname) VALUES(?,?,?);";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        preparedStatement.setString(1,"test");
        preparedStatement.setString(2,"test");
        preparedStatement.setString(3,"测试");

        int rows = preparedStatement.executeUpdate();
        System.out.println(rows);
        
        if(rows > 0){
            System.out.println("插入成功");
        }else{
            System.out.println("插入失败");
        }

        preparedStatement.close();
        connection.close();
    }

R、查询数据

行 id account password nickname
行 id account password nickname
行 id account password nickname

resultSet :
有行有列 获取数据时候,一行一数据
内部有一个游标,默认指向数据的第一行之前!
利用 next()方法移动游标 ,
指向数据行,再获取行中列的数据

MeteData
getColumnLabel先获取列的别名,没有别名用列名,用这个!
getColumnName只是列名

    /**
     * 查询全部数据!
     *   将数据存到List<Map>中
     *   一个map -> 对应一行数据
     *      map key -> 数据库列名或者别名
     *      map value -> 数据库列的值
     * 
     * 思路分析
     *    1.先创建一个List<Map>集合
     *    2.遍历resultSet对象的行数据
     *    3.将每一行数据存储到一个map对象中!
     *    4.将对象存到List<Map>中
     *    5.最终返回
     *
	 *  获取结果表头信息(列名和数量等信息)
     */
    @Test
    public void testQueryMap() throws SQLException, ClassNotFoundException {
        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/jdbc_test", "root", "root");

        String sql = "SELECT id,account,password,nickname FROM t_user;";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        ResultSet resultSet = preparedStatement.executeQuery();
        List<Map> mapList = new ArrayList<>();

        //获取列信息对象
    	//metaData装的是当前列的信息对象(通过他可以获取列对应的下角标,或者是列的数量)
        ResultSetMetaData metaData = resultSet.getMetaData();

    	//获取列的数量
        int columnCount = metaData.getColumnCount();
        while (resultSet.next()){
       		//一行数据对应一个map
            HashMap map = new HashMap();
            for (int i = 1; i <= columnCount; i++) {
                //参数:列名 与 值
                //next从第一行开始:第一列 的, 第一个数值 map -> 第二列 的, 第二个数字.... 列数结束退出for 下个next开始
                map.put(metaData.getColumnLabel(i),resultSet.getObject(i));
            }
            mapList.add(map);
        }
//[{password=123456, nickname=经理, id=1, account=root}, {password=666666, nickname=管理员, id=2, account=admin}]
        System.out.println(mapList);

        preparedStatement.close();
        connection.close();
        resultSet.close();
    }

非常麻烦的写法:
笨蛋写法

U、修改/更新 数据

    /**
     * 修改一条用户数据!
     * 修改账号: test的用户,将nickname改为临时
     */
    @Test
    public void testUpdate() throws SQLException, ClassNotFoundException {
        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc_test", "root", "root");

        String sql = "UPDATE t_user SET nickname = ? WHERE account = ?;";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        preparedStatement.setString(1,"临时");
        preparedStatement.setString(2,"test");

        int rows = preparedStatement.executeUpdate();
        System.out.println(rows);

        if(rows > 0){
            System.out.println("修改成功");
        }else{
            System.out.println("修改失败");
        }

        preparedStatement.close();
        connection.close();
    }

D、删除数据

    /**
     * 删除一条用户数据!
     * 根据账号: test
     */
    @Test
    public void testDelete() throws SQLException, ClassNotFoundException {
        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection connection = DriverManager.getConnection("jdbc:mysql:///jdbc_test", "root", "root");

        String sql = "DELETE FROM t_user WHERE account = ?;";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        preparedStatement.setString(1,"test");

        int rows = preparedStatement.executeUpdate();
        System.out.println(rows);

        if(rows > 0){
            System.out.println("删除成功");
        }else{
            System.out.println("删除失败");
        }

        preparedStatement.close();
        connection.close();
    }

六、preparedStatement 使用方式总结

1

//1.注册驱动

//2.获取连接

//3.编写SQL语句

//4.创建preparedstatement并且传入SQL语句结构

//5.占位符赋值

//6.发送SQL语句,并且获取结果 

//7.结果集解析

//8.关闭资源
//1.注册驱动
方案1: 调用静态方法,但是会注册两次
DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
方案2: 反射触发
Class.forName("com.mysql.cj.jdbc.Driver");

//2.获取连接

Connection connection = DriverManager.getConnection();

3 (String url,String user,String password)
2 (String url,Properties info(user password))
1 (String url?user=账号&password=密码 )

//3.创建statement

//静态
Statement statement = connection.createStatement();
//预编译
PreparedStatement preparedstatement = connection.preparedStatement(sql语句结构);

//4.占位符赋值

preparedstatement.setObject(?的位置 从左到右 从1开始,)

//5.发送sql语句获取结果

int rows = executeUpdate(); //非DQL
Resultset = executeQuery(); //DQL

//6.查询结果集解析

//移动光标指向行数据 next();  if(next())  while(next())
//获取列的数据即可   get类型(int 列的下角标 从1开始 | int 列的label (别名或者列名))
//获取列的信息   getMetadata(); ResultsetMetaData对象 包含的就是列的信息
                getColumnCount(); | getCloumnLebal(index)
//7.关闭资源
close(); 

七、JDBC 扩展

7.1 自增长主键回显实现

功能需求:

  1. java程序获取插入数据时mysql维护自增长维护的主键id值,这就是主键回显
  2. 作用: 在多表关联插入数据时,一般主表的主键都是自动生成的,所以在插入数据之前无法知道这条数据的主键,但是从表需要在插入数据之前就绑定主表的主键,这是可以使用主键回显技术:
/**
 * @Description: 返回插入的主键!
 */
public class PSAboutPrimaryKey {
    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        Class.forName("com.mysql.cj.jdbc.Driver");

        Connection connection = DriverManager.getConnection("jdbc:mysql:///jdbc_test?user=root&password=root");

        String sql = "insert into t_user(account,password,nickname) values (?,?,?);";
        // 第二个参数:告诉statement 要带回 数据库生成的主键值
        PreparedStatement preparedStatement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);

        preparedStatement.setObject(1,"doug");
        preparedStatement.setObject(2,"doug");
        preparedStatement.setObject(3,"道格");

        int rows = preparedStatement.executeUpdate();
        System.out.println(rows);

        // 结果集返回一个 只有主键的表 ; 固定使用getGeneratedKeys 来获取
        ResultSet resultSet = preparedStatement.getGeneratedKeys();
        //从第一行之前往下移一行
        resultSet.next();
        // 指向第一列,获取值
        int anInt = resultSet.getInt(1);
        System.out.println("anInt "+anInt);//anInt 4

        preparedStatement.close();
        connection.close();
    }
}

7.2 批量数据插入性能提升

  • 功能需求
    1. 批量数据插入优化
    2. 提升大量数据插入效率
/**
 *改动了三处:(1)路径(2)必写values,且后面不加;(3)装货addBatch()最后executeBatch();
 * 批量细节:
 *    1.url?rewriteBatchedStatements=true
 *    2.insert 语句必须使用 values
 *    3.语句后面不能添加分号;
 *    4.语句不能直接执行,每次需要装货  addBatch() 最后 executeBatch();
 *
 * 批量插入优化!
 * @throws Exception
 */
@Test
public void  batchInsertYH() throws Exception{

    //1.注册驱动
    Class.forName("com.mysql.cj.jdbc.Driver");
    //2.获取连接
    Connection connection = DriverManager.getConnection
          ("jdbc:mysql:///jdbc_test?rewriteBatchedStatements=true","root","root");
    //3.编写SQL语句结构
    String sql = "insert into t_user (account,password,nickname) values (?,?,?)";
    //4.创建预编译的statement,传入SQL语句结构
    /**
     * TODO: 第二个参数填入 1 | Statement.RETURN_GENERATED_KEYS
     *       告诉statement携带回数据库生成的主键!
     */
    long start = System.currentTimeMillis();
    PreparedStatement statement = connection.prepareStatement(sql);
    for (int i = 0; i < 10000; i++) {

        //5.占位符赋值
        statement.setObject(1,"yoo"+i);
        statement.setObject(2,"yoo");
        statement.setObject(3,"批量"+i);
        //6.装车
        statement.addBatch();
    }

    //发车! 批量操作!
    statement.executeBatch();

    long end = System.currentTimeMillis();

    System.out.println("消耗时间:"+(end - start));


    //7.结果集解析

    //8.释放资源
    connection.close();
}

7.3 jdbc中数据库事务实现

事务详解 见总结部分

八、Druid连接池技术使用

九、JDBC使用优化以及工具类封装

十、基于CMS项目JDBC实战练习


总结

var是什么:
var不是关键字,它相当于是一种动态类型;
var动态类型是编译器根据变量所赋的值来推断类型;
var 没有改变Java的本质,var只是一种简便的写法,
就是说在定义局部变量时,任意什么类型都可以用var定义变量的类型会根据所赋的值来判断。
如何使用var:
resultset.getString()后面加.var,再按两下回车


类加载 : java文件 -> 编译 -> 【 class字节码文件 --> 类加载 --> jvm虚拟中 --> Class对象】

类加载具体步骤
加载 【class文件转成对象加载到虚拟机中】->
连接 【验证(检查类文件) -> 准备 (静态变量赋默认值) -> 解析 (调用静态代码块) 】 ->
初始化 -> (赋真实值)

以下7种方式会触发类加载

  1. new关键字
  2. 调用静态属性
  3. 调用静态方法
  4. 接口 包含1.8 新特性 default关键字
  5. 反射 【Class.forName() 类名.class】
  6. 子类调用会触发父类的静态代码块
  7. 触发类的入口方法main

  • 重写: 为了子类扩展父类的方法!父类也间接的规范了子类方法的参数和返回!
  • 重载: 重载一般应用在第三方的工具类上,为了方便用户多种方式传递参数形式!简化形式!

事务:

  1. 数据库事务就是一种SQL语句执行的缓存机制,不会单条执行完毕就更新数据库数据,最终根据缓存内的多条语句执行结果统一判定!
  2. 一个事务内所有语句都成功及事务成功,我们可以触发commit提交事务来结束事务,更新数据!
  3. 一个事务内任意一条语句失败,及事务失败,我们可以触发rollback回滚结束事务, 数据回到事务之前状态!
  4. 也就是:允许我们在失败情况下,数据回归到业务之前的状态!
  5. 使用场景: 一个业务涉及多条修改数据库语句!
    例如: 经典的转账案例,转账业务(加钱和减钱)
    批量删除(涉及多个删除)
    批量添加(涉及多个插入)

事务特性:

  1. 原子性 (Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。

  2. 一致性(Consistency)事务必须使数据库从一个一致性状态变换到另外一个一致性状态。

  3. 隔离性(Isolation)事务的隔离性是指一个事务的执行不能被其他事务干扰,
    即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

  4. 持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响

事务类型:

  • 自动提交 : 每条语句自动存储一个事务中,执行成功自动提交,执行失败自动回滚! (MySQL)
  • 手动提交: 手动开启事务,添加语句,手动提交或者手动回滚即可!

SQL开启事务方式【事务都在一个连接中】
针对自动提交: 关闭自动提交即可,多条语句添加以后,最终手动提交或者回滚! (推荐)

      SET autocommit = off; //关闭当前连接自动事务提交方式
      # 只有当前连接有效
      # 编写SQL语句即可
      SQL
      SQL
      SQL
      #手动提交或者回滚 【结束当前的事务】
      COMMIT / ROLLBACK ;

手动开启事务: 开启事务代码,添加SQL语句,事务提交或者事务回滚! (不推荐)

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

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

相关文章

抖音小店2024年创业新趋势,新手找项目,不要再错过这次的机会了

大家好&#xff0c;我是电商花花。 现在的抖音小店完全是电商创业中的一个优秀代名词和最轻便的创业项目&#xff0c;更是以独特的直播达人带货的优势将店铺激发出来。 今天给大家介绍下抖音小店的运作方式&#xff0c;并分析互联网创业的机遇&#xff0c;并提供相关的再做点…

华为交换机配置NQA DNS检测IP网络DNS解析速度

华为HCIA视频教程&#xff1a;超级实用&#xff0c;华为VRP系统文件详解 华为HCIA视频教程&#xff1a;不会传输层协议&#xff0c;HCIA都考不过 华为HCIA视频教程&#xff1a;网络工程师的基本功&#xff1a;网络地址转换NAT 华为HCIP视频教程&#xff1a;DHCP协议原理与配…

IDEA、CLion代码智能提示功能忽略大小写

代码提示和补充功能有一个特性&#xff1a;区分大小写。 如果想不区分大小写的话&#xff0c;就把这个对勾去掉。建议去掉勾选。

acwing BFS

BFS BFS 重点就是要使用 队列 进行每一层的搜索不同题目 队列中保存的元素形式都各不相同&#xff0c;并且也会用到其他辅助结构走迷宫一题&#xff0c;队列中存的是每一层(当前步能走的所有坐标)的坐标&#xff0c;并保存了每一层对应走过的步数八数码一题&#xff0c;队列中…

使用CLIP和LLM构建多模态RAG系统

在本文中我们将探讨使用开源大型语言多模态模型(Large Language Multi-Modal)构建检索增强生成(RAG)系统。本文的重点是在不依赖LangChain或LLlama index的情况下实现这一目标&#xff0c;这样可以避免更多的框架依赖。 什么是RAG 在人工智能领域&#xff0c;检索增强生成(re…

【html+css+js】实例自习笔记–前端基础知识–绝对定位的盒子水平居中

【htmlcssjs】实例自习笔记–前端基础知识–绝对定位的盒子水平居中 【CSS面试题】绝对定位的盒子水平居中 问题&#xff1a; 代码如图 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"view…

Spring上下文之support模块MessageSourceAccessor

博主介绍&#xff1a;✌全网粉丝5W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

DNS从入门到精通

DNS从入门到精通 Dns从入门到精通 DNS从入门到精通一、DNS原理二、企业高速缓存dns的搭建三、DNS相关名词解释四、权威DNS搭建编辑子配置文件&#xff08;主要写我们维护的域zone)开始解析 五、权威dns中的数据记录种类及应用编辑子配置文件&#xff08;主要写我们维护的域zone…

【LeetCode: 208. 实现 Trie (前缀树)】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

关于晶振回流焊工艺,你知道哪些呢!

晶振&#xff0c;作为现代电子设备中的核心元件&#xff0c;其制造过程需要经过多道精密的工艺流程。其中&#xff0c;回流焊工艺是晶振制造过程中一个至关重要的环节。本文将详细介绍回流焊工艺在晶振制造中的应用&#xff0c;以及关键的注意事项。 一、回流焊工艺简介 回流…

划重点!多微信号一键定时发圈,省时省力!

发朋圈对于很多职场人来说是一种社交媒体营销和个人品牌建设的重要手段。 然而&#xff0c;一个人面对几个微信号的朋友圈&#xff0c;难免会有应付不过来的时候&#xff0c;这时候只需要一个个微管理管理系统&#xff0c;就能帮你一键定时发圈&#xff0c;省去重复发布的时间…

(2023版)斯坦福CS231n学习笔记:DL与CV教程 (1) | 引言与知识基础

前言 &#x1f4da; 笔记专栏&#xff1a;斯坦福CS231N&#xff1a;面向视觉识别的卷积神经网络&#xff08;23&#xff09;&#x1f517; 课程链接&#xff1a;https://www.bilibili.com/video/BV1xV411R7i5&#x1f4bb; CS231n: 深度学习计算机视觉&#xff08;2017&#xf…

Mybatis 分页插件 PageHelper

今天记录下 Mybatis 分页插件 pageHelper 的使用。 背景 有一个员工表(employee)&#xff0c;现在要使用 pageHelper 插件实现员工的分页查询。 员工表 create table employee (id bigint auto_increment comment 主键primary key,name varchar(32) not …

springboot基于WEB的旅游推荐系统设计与实现

&#x1f345;点赞收藏关注 → 私信领取本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345;一 、设计说明 1.1选题动因 当前…

Unity使用Protobuf

1.下载Protobuf ProtoBuf 2.打开它并且编译 如果有报错下载相应的.net版本即可 这里默认是6.0.100 由于我本机是8.0.100所以我改了这个文件 3.编译后的文件复制到Unity Assets/Plugins下 4.写个测试的proto文件 5.然后使用protoc生成 这里实现了一个简单的bat批量生成 Protos C…

postman上传文件文件名有黄色图标

问题&#xff1a; 解决方案 步骤一&#xff1a;设置处打开settings 步骤二&#xff1a;打开location&#xff0c;选择文件所在磁盘目录 步骤三&#xff1a;关闭选项框 文件报错问题解决

cmd输入Python后Python环境无反馈,空

我用cmd输入Python后Python环境无反馈没打开Python环境。 解决方法&#xff1a; 一、打开电脑 [设置] 或 [控制面板] &#xff1b; 二、点到 [系统] 或 [系统和安全] 后&#xff0c;你要看一下找到 [系统信息] 然后点击&#xff1b; 三、 [高级系统设置] 点击后跳出 [系统属…

Pixart PAR2861 蓝牙 keyboard 开发笔记

Pixart PAR2861 是一款采用32 bits ARM Cortex-M0 低功耗、高效能 2.4GHz RF 的 SoC。 该 SoC 整合了高效能的 2.4GHz RF 收发器、硬体Keyscan、硬体按键防弹跳、SPI、I2C、PWM LED、ADC、UART等。内建 DC/DC 转换器和 LDO 为独立 HID 应用提供完整的低功耗 SoC 解决方案。 1.…

uniapp下各端调用三方地图导航

技术栈 开发框架&#xff1a; uniappvue 版本&#xff1a; 2.x 需求 使用uniapp在app端(Android&#xff0c;IOS)中显示宿主机已有的三方导航应用&#xff0c;由用户自主选择使用哪家地图软件进行导航&#xff0c;选择后&#xff0c;自动将目标地址设为终点在导航页面。 使用…

宋仕强论道之华强北的“熵增”定律(四十二)

熵增”是热力学第二定律概念&#xff0c;描述了关于生命体的能量耗散的问题&#xff0c;即当一个封闭系统内没有新的能量输入时&#xff0c;就会逐渐失能无序发展至混乱直至混沌状态,后面我还会讲到“华强北的焓值”。华强北目前的情况就是“熵增”现象非常严重&#xff0c;人流…