MyBatis操作数据库(一)

什么是MyBatis?
MyBatis是一个优秀的持久层框架,⽤于简化JDBC的开发。
MyBatis本是Apache的⼀个开源项⽬iBatis,2010年这个项目由apache迁移到了googlecode,并且改名为MyBatis。
简单来说MyBatis是更加简单完成数据和数据库交互的框架

什么是持久层呢?
web应⽤程序⼀般分为三层,有Controller、Service、
Dao流程如下浏览器发起请求,先请求Controller,Controller接收到请求之后Service进⾏业务逻辑处理Service再调⽤Dao。而持久层就是持久操作的层,就是数据访问层dao,是用来操作数据库

MyBatis入门
(1)创建spingboot工程、并导入mybatis起步依赖、mysql的驱动包
在这里插入图片描述
Mybatis 是⼀个持久层框架,具体的数据存储和数据操作还是在MySQL中操作的,所以需要添加MySQL驱动
我们可以看到创建完成之后pom.xml文件中导入的依赖
在这里插入图片描述
(2)
创建对应的UserInfo

package com.example.mybatisdemo.demos.web;import javax.xml.crypto.Data;public class UserInfo {private Integer id;private String usernane;private String password;private Integer age;private Integer gender;private String phone;private Integer deleteFlag;private Data createTime;private Data updateTime;
}

数据准备创建用户表 并创建对应的实体类User

DROP DATABASE IF EXISTS mybatis_test;
create database mybatis_test default character set utf8mb4;
use mybatis_test;
DROP TABLE IF EXISTS userinfo;CREATE TABLE `userinfo` (`id` INT ( 11 ) NOT NULL AUTO_INCREMENT,`username` VARCHAR ( 127 ) NOT NULL,`password` VARCHAR ( 127 ) NOT NULL,`age` TINYINT ( 4 ) NOT NULL,`gender` TINYINT ( 4 ) DEFAULT '0' COMMENT '120默认 ',`phone` VARCHAR ( 15 ) DEFAULT NULL,`delete_flag` TINYINT ( 4 ) DEFAULT 0 COMMENT '0正常, 1删除 ',`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now(),PRIMARY KEY ( `id` )) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )VALUES ( 'admin', 'admin', 18, 1, '18612340001' );INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' );INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' );INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )VALUES ( 'wangwu', 'wangwu', 18, 1, '18612340004' );

配置数据库连接字符串
配置application.yml文件

#数据库连接配置

spring:datasource:url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false#username: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driver

如果使⽤MySQL是5.x之前的使用的 是"com.mysql.jdbc.Driver",如果是⼤于5.x使用的
是“com.mysql.cj.jdbc.Driver”

写入持久层代码
在项目中建立持久层接口UserIonfoMapper

package com.example.mybatisdemo.demos.web.mapper;import com.example.mybatisdemo.demos.web.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;import java.util.List;@Mapper
public interface UserInfoMapper {//查询所有用户@Select("select username, 'password',age, gender, phone from userinfo")public List<UserInfo> queryAllUser();
}

@Mapper注解:表示是MyBatis中的接口

程序运⾏时,框架会⾃动⽣成接⼝的实现类对象(代理对象),并给交Spring的IOC容器管理

@Select注解:代表的就是select查询,也就是注解对应⽅法的具体实现内容

单元测试
创建出来的SpringBoot⼯程中,在src下的test⽬录下,已经⾃动帮我们创建好了测试类,我们可以直接使⽤这个测试类来进⾏测试

package com.example.mybatisdemo;import com.example.mybatisdemo.demos.web.UserInfo;
import com.example.mybatisdemo.demos.web.mapper.UserInfoMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.util.List;@SpringBootTest
class MyBatisdemoApplicationTests {@Autowiredprivate UserInfoMapper userInfoMapper;@Testvoid contextLoads() {List<UserInfo> userInfoList = userInfoMapper.queryAllUser();System.out.println(userInfoList);}}

测试类有注解@SpringBootTest在运⾏时⾃动加载Spring的运⾏环境通过@Autowired这个注解,注⼊我们要测试的类,就可以开始进⾏测试了

然后结果中只有SQL语句中查询的列对应的属性才有赋值
在这里插入图片描述

使用idea自动生成测试类
除此之外,也可以使⽤Idea⾃动⽣成测试类
在使用Mapper接口时
右键->Generate->Test
在这里插入图片描述

在这里插入图片描述
编写代码

package com.example.mybatisdemo.demos.web.mapper;import com.example.mybatisdemo.demos.web.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.util.List;import static org.junit.jupiter.api.Assertions.*;@SpringBootTestclass UserInfoMapperTest {@Autowiredprivate UserInfoMapper userInfoMapper;@Testvoid queryAllUser() {List<UserInfo> userInfoList = userInfoMapper.queryAllUser();System.out.println(userInfoList);}
}

在这里插入图片描述

MyBatis的基础操作

打印MyBatis日志我们借助日志查看sql语句执行 执行传递的参数和执行结果
配置文件

#数据库连接配置
mybatis:configuration: #配置打印MyBatis日志log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

重新运行查看结果
在这里插入图片描述

其中
表示:查询语句

Preparing: select username, 'password',age, gender, phone from userinfo

表示:查询类型

Parameters:

表示: 查询SQL语句结果

<==    Columns: username, password, age, gender, phone
<==        Row: admin, password, 18, 1, 18612340001
<==        Row: zhangsan, password, 18, 1, 18612340002
<==        Row: lisi, password, 18, 1, 18612340003
<==        Row: wangwu, password, 18, 1, 18612340004
<==      Total: 4

参数传递
需求:查找id为4的用户

@Mapper
public interface UserInfoMapper {//查询所有用户@Select("select username, 'password',age, gender, phone from userinfo")List<UserInfo> queryAllUser();@Select("select username, 'password', age, gender, phone from userinfo where id = 4")UserInfo queryById();
}

生成测试用例

在这里插入图片描述

package com.example.mybatisdemo.demos.web.mapper;import com.example.mybatisdemo.demos.web.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import static org.junit.jupiter.api.Assertions.*;
@SpringBootTestclass UserInfoMapperTestquerById {@Autowiredprivate UserInfoMapper userInfoMapper;@Testvoid queryById() {UserInfo userInfo = userInfoMapper.queryById();System.out.println(userInfo);}
}

结果
@Select(“select username, ‘password’, age, gender, phone from userinfo where id = #{id}”)
UserInfo queryById(Integer id);在这里插入图片描述
但是这样的话, 只能查找id=4的数据,所以SQL语句中的id值不能写成固定数值,需要变为动态的数值解决⽅案:在queryById⽅法中添加⼀个参数(id),将⽅法中的参数,传给SQL语句
例如:

   @Select("select username, 'password', age, gender, phone from userinfo where id = #{id}")UserInfo queryById(Integer id);@Testvoid queryById() {UserInfo userInfo = userInfoMapper.queryById(4);System.out.println(userInfo);}

结果
在这里插入图片描述
也可以通过注解@Param设置参数别名#{…}里面的属性名要和@Param里面的一样

@Select("select username, `password`, age, gender, phone from userinfo where 
id= #{userid} ")UserInfo queryById(@Param("userid") Integer id);

MyBatis的增删查改

SQL语句

insert into userinfo (username, `password`, age, gender, phone) values 
("zhaoliu","zhaoliu",19,1,"18700001234")

我们把sql中的常量换成动态的参数
例如:

@Insert("insert into userinfo(username,'password',age,gender,phone) values (#{username},#{password},#{age},#{gender},#{phone})")Integer insert(UserInfo userInfo);

生成测试案例

在这里插入图片描述

package com.example.mybatisdemo.demos.web.mapper;import com.example.mybatisdemo.demos.web.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
class UserInfoMapperTestInsert {@Autowiredprivate  UserInfoMapper userInfoMapper;@Testvoid insert() {UserInfo userInfo = new UserInfo();userInfo.setUsername("zhaoliu");userInfo.setPassword("zhaoliu");userInfo.setGender(2);userInfo.setAge(21);userInfo.setPhone("18612340005");userInfoMapper.insert(userInfo);}
}

在这里插入图片描述
也可以设置使用@Param属性 使用#{…} 需要参数.属性获取

 @Insert("insert into userinfo (username, password, age, gender, phone) values (#{userinfo.username},#{userinfo.password},#{userinfo.age},#{userinfo.gender},#{userinfo.phone})")Integer insert(@Param("userinfo")UserInfo userinfo);

返回主键
Insert语句默认返回的是受影响行数
有些情况数据插入之后还需要用于后续的关联操作需要新插入数据的id
如果我们想拿到自增id就要在mapper接口上添加一个
@Options注解
例如:

 @Options(useGeneratedKeys = true, keyProperty = "id")
@Insert("insert into userinfo (username, password, age, gender, phone) values (#{userinfo.username},#{userinfo.password},#{userinfo.age},#{userinfo.gender},#{userinfo.phone})")Integer insert(@Param("userinfo")UserInfo userinfo);

useGeneratedKeys:
这会令 MyBatis 使⽤ JDBC 的 getGeneratedKeys ⽅法来取出由数据库内的部⽣成的主键(⽐如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的⾃动递增字
段),默认值:false.
keyProperty:指定能够唯⼀识别对象的属性,MyBatis 会使⽤ getGeneratedKeys 的返回值或insert 语句的 selectKey ⼦元素设置它的值,默认值:未设置(unset)

测试:

 @Testvoid insert() {UserInfo userInfo = new UserInfo();userInfo.setUsername("zhaoliu");userInfo.setPassword("zhaoliu");userInfo.setGender(2);userInfo.setAge(21);userInfo.setPhone("18612340005");Integer count =userInfoMapper.insert(userInfo);System.out.println(userInfo);System.out.println("添加数据条数" + count +",数据ID:" + userInfo.getId());}

结果:
在这里插入图片描述
在这里插入图片描述

删除:
对应sql语句

delete from userinfo where id=6
  @Delete("delete from userinfo where id = #{id}")void delete(Integer id);

生成测试案例

 @Testvoid delete() {userInfoMapper.delete(9);}

运行结果
在这里插入图片描述
在这里插入图片描述
改:
对应sql语句

update userinfo set username="xiaozhao" where id=8

接口

@Update("update userinfo set username=#{username} where id=#{id}")void update(UserInfo userInfo);

测试代码

  @Testvoid update() {UserInfo userInfo = new UserInfo();userInfo.setUsername("lisi");userInfo.setId(8);Integer result = userInfoMapper.update(userInfo);if (result>0){System.out.println("修改成功");}}

结果:
在这里插入图片描述
在这里插入图片描述
查:
我们对表上的数据进行查询

 @Select("select id, username,password,age,gender,phone,delete_flag,create_time,update_time from userinfo")List<UserInfo> queryALLUser2();

生成的测试类:

@Testvoid queryALLUser2() {List<UserInfo> userInfoList = userInfoMapper.queryALLUser2();System.out.println(userInfoList);

结果:
我们可以看到表中的delete_flag,create_time,update_time查询到了却没有附上属性的值
在这里插入图片描述

MyBatis 会根据⽅法的返回结果进⾏赋值 ⽅法⽤对象 UserInfo接收返回结果, MySQL 查询出来数据为⼀条,
就会⾃动赋值给对象 ⽅法⽤List接收返回结果, MySQL 查询出来数据为⼀条或多条时, 也会⾃动赋值给List
但如果MySQL 查询返回多条, 但是⽅法使⽤UserInfo接收, MyBatis执⾏就会报错.

这是因为当自动映射查询结果时,MyBatis会获取结果中返回的列名并在 Java 类中查找相同名字的属性(忽略
⼤⼩写)这意味着如果发现了 ID 列和 id 属性,MyBatis 会将列 ID 的值赋给 id 属性 如果不一致就不会赋值

在这里插入图片描述
在这里插入图片描述
可以看到后面三个的名字不一致
这时我们怎么解决呢?

  1. 起别名
    在SQL语句给列名起别名保持别名和实体类属性名一样
    例如:
    @Select("select id, username, password,age, gender, phone,delete_flag as deleteFlag, " +"create_time as createTime, update_time as updateTime" +" from userinfo")List<UserInfo> queryAllUser();

测试案例:

   @Testvoid queryAllUser() {List<UserInfo> userInfoList = userInfoMapper.queryAllUser();log.info(userInfoList.toString());}

运行结果:
在这里插入图片描述
这里就可以看到之前本为空的
delete_flag 和 create_time 被起别名成createTime
updateTime(和userInfo的属性名对上)之后就能赋值上了

错误笔记:
之前这里的的updateTime和createTime就算改了别名之后赋值还是null找了很久都没有发现错误,最后发现是属性的类型对不上
在这里插入图片描述
这里的类型的包应该是这个包的
在这里插入图片描述
但是我没注意用了这个包的Date从而导致代码看起来是对的但是结果不对
在这里插入图片描述
所以当我们发现mybatis查询值为null时可以从以下几个方面排除

  1. 数据库对应的纪录的字段确实为空;
  2. 映射配置问题:确保在数据库映射配置(比如 MyBatis 的配置)中,对于这两个时间字段的映射处理是正确的。
  3. 查询语句问题: 检查查询语句中对于这两个字段的获取和别名设置是否准确无误
  4. 数据类型不匹配 例如: 代码中定义的 Data 类型与数据库中实际的时间字段类型不匹配,导致无法正确映射。

(2) 结果映射

@Results(id = "BaseMap",value = {@Result(column = "delete_flag",property = "deleteFlag"),@Result(column = "create_time",property = "createTime"),@Result(column = "update_time",property = "updateTime")})@Select("select * from userinfo")

测试类

@Testvoid testQueryALLUser2() {List<UserInfo> userInfoList = userInfoMapper.queryAllUser2();log.info(userInfoList.toString());}

结果:
在这里插入图片描述
如果我们也希望其他的SQL语句使用这个映射关系
可以使用注解@ResultMap注解来复用其他定义的ResultMap
例如:

运行结果:

    @Select("select id, username, password,age,gender,phone,delete_flag,create_time,update_time " +"from userinfo where id = #{userid}")@ResultMap(value = "BaseMap")UserInfo queryByid(@Param("userid") Integer id);

测试类

@Testvoid queryByid() {UserInfo userInfo =  userInfoMapper.queryByid(3);log.info(userInfo.toString());}

在这里插入图片描述

开启驼峰命名
通常数据库列使⽤蛇形命名法(下划线分割各个单词)
Java 属性⼀般遵循驼峰命名法约定为了在这两种命名⽅式之间启⽤⾃动映射
需要将 mapUnderscoreToCamelCase 设置为 true
例如:

mybatis:configuration: #配置打印MyBatis日志log-impl: org.apache.ibatis.logging.stdout.StdOutImplmap-underscore-to-camel-case: true

驼峰命名规则: abc_xyz => abcXyz
表中字段名:abc_xyz
类中属性名:abcXyz
这时我们java代码不做任何处理就可以通过驼峰命名自动转换
例如:

   @Select("select id, username, password,age,gender,phone,delete_flag,create_time,update_time " +"from userinfo")List<UserInfo> selectAllUser();
@Testvoid selectAllUser() {List<UserInfo> userInfoList = userInfoMapper.selectAllUser();log.info(userInfoList.toString());}

结果
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2-6 基于matlab2018B的语音信号降噪和盲源分离GUI界面

基于matlab2018B的语音信号降噪和盲源分离GUI界面&#xff0c;包括维纳滤波&#xff0c;小波降噪、高通、低通、带通滤波&#xff0c;及提出的滤波方法。每个功能均展示降噪前后声音效果并外放出来。程序已调通&#xff0c;可直接运行。 2-6 语音信号降噪 盲源分离 GUI界面 - 小…

canvas学习

Canvas API 提供了一个通过 JavaScript 和 HTML 的 元素来绘制图形的方式。它可以用于动画、游戏画面、数据可视化、图片编辑以及实时视频处理等方面。 Canvas 的基本用法 <canvas> 元素 <canvas id"tutorial" width"150" height"150&quo…

[Python]Anaconda相关命令

环境操作相关命令 查看所有环境 conda env list创建环境 conda create --name cahttts python3.10激活环境 conda activate cahttts安装依赖文件 pip install -r requirements.txt查看GPU型号 nvidia-smi -LGPU 0: NVIDIA A10 (UUID: GPU-9f1fc9cf-582a-25ac-849c-2f77343…

ESD与EOS区别

最近小白在做项目时&#xff0c;被一个实习生问道了&#xff0c;关于EOS与ESD区别。说实话&#xff0c;以前专注于测试debug的我&#xff0c;在回答对方时&#xff0c;并没法做到太全面的解答。于是乎&#xff0c;借助周内的空闲时间&#xff0c;小白还是简单学习总结了一番。 …

Harbor镜像中心搭建

文章目录 Harbor镜像中心搭建前置条件下载Harbor创建CA证书配置Harbor开始启动地址映射访问配置本地登录配置外部虚拟机访问 Harbor镜像中心搭建 Harbor是一个镜像中心&#xff0c;我们所熟知的DockerHub就是一个镜像中心&#xff0c;我们可以把我们打包的镜像放在镜像中心中供…

关于Java

关于Java Java语言关于并发JVM调优工具写在最后 Java语言 Java语言作为当下主流开发语言&#xff0c;其面向对象的开发模式以及一次编译多次运行&#xff0c;跨平台运行以及自动的垃圾回收机制可以说是给开发者节省了很大的时间用于逻辑功能的开发&#xff0c;那么在开发过程中…

【Linux】pycharmgit相关操作

目录 1. git安装配置2. 相关内容3. pycharm连接远程仓库3.1 配置3.2 clone远程仓库3.3 本地仓库上传远程 4. 分支管理4.1 更新代码4.2 新建分支4.3 分支合并4.4 代码比对 5. 版本管理6. 命令行操作6.1 配置git6.2 基础操作6.3 分支操作 1. git安装配置 下载链接&#xff1a;官…

07--Zabbix监控告警

前言&#xff1a;和普米一样运维必会的技能&#xff0c;这里总结一下&#xff0c;适用范围非常广泛&#xff0c;有图形化界面&#xff0c;能帮助运维极快确定问题所在&#xff0c;这里记录下概念和基础操作。 1、zabbix简介 Zabbix是一个基于 Web 界面的企业级开源解决方案&a…

【C++】C++入门的杂碎知识点

思维导图大纲&#xff1a; namespac命名空间 什么是namespace命名空间namespace命名空间有什么用 什么是命名空间 namespace命名空间是一种域&#xff0c;它可以将内部的成员隔绝起来。举个例子&#xff0c;我们都知道有全局变量和局部变量&#xff0c;全局变量存在于全局域…

SQLAlchemy:filter()和filter_by()的微妙差异

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; 在Python编程中&#xff0c;SQLAlchemy是一个强大的ORM&#xff08;对象关系映射&#xff09;工具&#xff0c;它允许使用Python代码来操作数据库。然而&#xff0c;对于新手来说&#xff0c;SQLAlchemy中的一些函数…

mybatis-plus使用拦截器实现sql完整打印

shigen坚持更新文章的博客写手&#xff0c;擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长&#xff0c;分享认知&#xff0c;留住感动。 个人IP&#xff1a;shigen 在使用mybatis-plus&#xff08;mybatis&#xff09;的时候&#xff0c;往往需要…

英伟达开源最强通用模型Nemotron-4 340B:开启AI合成数据新纪元

【震撼发布】 英伟达最新力作——Nemotron-4 340B,一个拥有3400亿参数的超级通用模型,震撼登场!这不仅是技术的一大飞跃,更是AI领域的一次革命性突破! 【性能卓越】 Nemotron-4 340B以其卓越的性能超越了Llama-3,专为合成数据而生。它将为医疗健康、金融、制造、零售等行…

Studio One 6.6.2 for Mac怎么激活,有Studio One 6激活码吗?

如果您是一名音乐制作人&#xff0c;您是否曾经为了寻找一个合适的音频工作站而苦恼过&#xff1f;Studio One 6 for Mac是一款非常适合您的MacBook的音频工作站。它可以帮助您轻松地录制、编辑、混音和发布您的音乐作品。 Studio One 6.6.2 for Mac具有直观的界面和强大的功能…

C++初学者指南第一步---1. C++开发环境设置

C初学者指南第一步—1. C开发环境设置 目录 C初学者指南第一步---1. C开发环境设置1.1 工具1.1.1 代码编辑器和IDE1.1.2 Windows1.1.3 命令行界面 1.2 编译器1.2.1 gcc/g (支持Linux/Windows/MacOSX)1.2.2 clang/clang (支持Linux/Windows/MacOS)1.2.3 Microsoft Visual Studio…

《面向对象程序设计》第3章 类与对象(判断、选择、填空)-练习

1-1 常量对象可以使用常量成员函数。 T F | 参考答案 答案 T 2分 1-2 在定义常量成员函数和声明常量成员函数时都应该使用const关键字。 T F | 参考答案 答案 T 2分 1-3 对象间赋值将调用拷贝构造函数。 T F | 参考答案 答案 F 2分 1-4 对象数组生命期…

奇思妙想-可以通过图片闻见味道的设计

奇思妙想-可以通过图片闻见味道的设计 偷闲半日享清闲&#xff0c;炭火烧烤乐无边。肉串飘香引客至&#xff0c;笑语欢声绕云间。人生难得几回醉&#xff0c;且把烦恼抛九天。今宵共饮开怀酒&#xff0c;改日再战新篇章。周四的傍晚&#xff0c;难得的闲暇时光让我与几位挚友相…

PAT B1026. 程序运行时间

题目描述 要获得一个C语言程序的运行时间,常用的方法是调用头文件time.h,其中提供了clock(&#xff09;函数,可以捕捉从程序开始运行到clock()被调用时所耗费的时间。这个时间单位是clock tick,即“时钟打点”。同时还有一个常数CLK_TCK——给出了机器时钟每秒所走的时钟打点数…

继电器的保护二极管如何选择

继电器在实际应用中&#xff0c;通常都会使用三极管或MOS管控制&#xff0c;其最基本的应用电路如图&#xff1a; 那为什么要在继电器线圈上并联一个二极管呢&#xff1f;我们可以看看没有并联二极管时电路会出现什么情况&#xff0c;我们使用下图所示的电路参数仿真一下&#…

食家巷助力“甘肃乡村振兴,百强主播·打call 甘味”活动

2024年&#xff0c;甘肃省“商务乡村振兴”促消费暨“百强主播打call 甘味”活动在天水市龙城广场盛大启动。 活动现场&#xff0c;来自甘肃省 14 个市州的农特产品展台琳琅满目&#xff0c;让人目不暇接。此次活动中&#xff0c;各企业带来了多款深受消费者喜爱的产品&a…

【AI实践】Dify调用本地和在线模型服务

背景 Ollama可以本地部署模型&#xff0c;如何集成私有数据、如何外部应用程序对接&#xff0c;因此需要有一个应用开发框架 Dify功能介绍 欢迎使用 Dify | 中文 | Dify 下文将把dify部署在PC上&#xff0c;windows环境&#xff1b; 安装部署 安装dify及docker jacobJacobs…