Mybatis的出现 是为了简化JDBC的复杂操作,而Mybatis-plus的出现则是为了简化Mybatis的操作,它不会改变mybatis原有的东西,只会在原有的基础上增加功能,可以说,它是非入侵式的,蕴含了AOP的思想
User
表,其表结构如下:id | name | age | |
---|---|---|---|
1 | Jone | 18 | [email protected] |
2 | Jack | 20 | [email protected] |
3 | Tom | 28 | [email protected] |
4 | Sandy | 21 | [email protected] |
5 | Billie | 24 | [email protected] |
DROP TABLE IF EXISTS user;
CREATE TABLE user
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, '[email protected]'),
(2, 'Jack', 20, '[email protected]'),
(3, 'Tom', 28, '[email protected]'),
(4, 'Sandy', 21, '[email protected]'),
(5, 'Billie', 24, '[email protected]');
创建一个SpringBoot项目
添加MybatisPlus启动器依赖
<!-- mybatis-plus-启动器 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
编写实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
编写Mapper类
@Mapper
@Repository
public interface UserMapper extends BaseMapper<User> {
}
/*
继承BaseMapper<T>类 T是一个泛型 这里填入我们的实体类
我们就可以直接使用MybatisPlus为我们封装好的CRUD方法
*/
编写数据库数据源和日志
#数据库连接配置 mysql 8.0版本的多了时区设置 GMT%2b8就是我们东八区的时区
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis-plus?serverTimezone=GMT%2b8
username: root
password: 123456
#日志配置 默认控制台输出 这里我们使用默认的日志输出
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
测试
@Autowired
UserMapper userMapper;
@Test
void contextLoads() {
List<User> users = userMapper.selectList(null);
for (User user : users) {
System.out.println(user);
}
}
这样 我们的Mybatis-Plus环境就算搭建完成了
查看insert的方法 只有一个 返回值是一个entity实体类对象
我们在不插入ID的情况下 进行测试看看发生什么
//插入测试
@Test
public void text1(){
User user = new User();
user.setAge(18);
user.setName("狂神");
user.setEmail("[email protected]");
userMapper.insert(user);
}
通过控制台输出 我们发现 它自动给我们生成了一个Long类型的数字 那么它是怎么来的呢?
原来,Mybatis-plus的insert语句中,内置了主键自增策略,当我们的ID为NULL时,它会自动给我们生成一串数字,这串数字是由雪花算法
产生的,而产生的前提是ID的类型必须为Long
类型,雪花算法也是它的默认类型
注意:
如果我们的ID类型为其他类型。且插入的时候为NULL 运行程序就会报错
Caused by:
org.apache.ibatis.reflection.ReflectionException: Could not set property 'id' of 'class com.llf.Pojo.User' with value '1418934148565385218' Cause: java.lang.IllegalArgumentException: argument type mismatch
翻译:无法将long类型的值'1418934148565385218'赋给ID
说白了 它就是一种随机生成主键的算法 它有以下特点
在mybatis-plus中,除了默认的雪花算法还有许多主键生成策略
ASSIGN_ID
Twitter的分布式自增ID算法
雪花算法 就是我们默认的主键生成策略
形式:1418884175761063937
ASSIGN_UUID
形式:6904b36e-e220-2fcf-4e00-23c3449e1e24
随机生成UUID,UUID 是 通用唯一识别码(Universally Unique Identifier)的缩写 优点是
优点:性能非常高,JDK自带本地生成,无网络消耗
缺点:(1)只保证了唯一性,趋势递增。
(2)无序,无法预测他的生成规则,不能生成递增有序的数字。
(3)mysql官方推荐主键越短越好,UUID包含32个16位进制的字母数字,每一个都很长。
(4)B+树索引的分裂。主键是包含索引的,mysql的索引是通过B+树来实现的,因为UUID是无序的,插入无序,不但会导致一些中间节点产生分裂,也会白白创造很多不饱和的节点,大大降低了数据库插入的性能。
AUTO
主键自增,也是最简单的主键生成策略,但是实现的前提必须是数据库必须打开主键自增的设置
INPUT
自己输入 即自己Set注入
User user = userMapper.selectById(1l);
user.setId(2L);
userMapper.updateById(user);
NONE
什么也不输入 如果这张表中没有主键,即为NULL 但基本上不会这么做。
物理删除
:delete 语句就是物理删除 一旦删除 就没有了
逻辑删除
:通过代码设置 在查询的时候不显示 实际上数据库中还有 只是状态不同了 类似于回收站
deleteById
通过单个id删除
deleteBatchIds
通过多个id同时删除
deleteByMap
通过一个Map集合删除
@Test
public void text5(){
userMapper.deleteById(1418846421555712001l);
System.out.println("通过id删除成功");
userMapper.deleteBatchIds(Arrays.asList(1418844779586318338l,1418844779586318337l));
System.out.println("多个ID删除成功");
HashMap<String, Object> map = new HashMap<>();
map.put("id","10");
userMapper.deleteByMap(map);
System.out.println("通过map删除成功");
}
deleted
我们设定0为正常显示 1为不显示 并设置默认值为0
//逻辑删除注解
@TableLogic
private Integer deleted;
0
、1
显示设置mybatis-plus:
global-config:
db-config:
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
userMapper.deleteById(4);
System.out.println("通过id删除成功");
这时我们可以发现删除语句 在后台已经变成了更新语句
查询
@Test
void contextLoads() {
List<User> users = userMapper.selectList(null);
for (User user : users) {
System.out.println(user);
}
}
通过查询 和数据库查询 我们发现这些值在数据库中依然存在 只是查询不到了 这就表明实现了逻辑删除
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LI180oOJ-1627193026476)(C:\Users\machenike\AppData\Roaming\Typora\typora-user-images\image-20210725092011217.png)]
更新 只有两种方法 ,一种是传入一个对象,一种是传入对象+构造器Wrapper 关于构造器 我们这里先让他为null
update
传入一个对象 修改所有值 相当于普通更新 没有where
条件条件(Wapper构造器可以添加条件 但这里先不用)
@Test
public void text8(){
User user = new User();
user.setId(1418932799022907393L);
user.setAge(18);
user.setName("狂");
user.setEmail("[email protected]");
userMapper.update(user,null);
}
他把所有信息都更改了
顾名思义 传入一个对象 通过id修改内容
@Test
public void text8(){
User user1 = new User();
user1.setId(11L);
user1.setAge(1);
// userMapper.update(user,null);
userMapper.updateById(user1);
}
按照规范,我们在数据库设计的过程中会加入create_time、update_time,但是这些时间理论上应该是自动生成,而不是我们一个一个New Data()实现的 Mybatis-Plus就为我们完成了这个功能
//在插入时填充时间
@TableField(fill = FieldFill.INSERT_UPDATE )
private Date createTime;
//更新时更新时间
@TableField(fill = FieldFill.UPDATE)
private Date updateTime;
MetaObjectHandler
类,进行设置package com.llf.Handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
@Slf4j
//添加@Componment注解 表示被Spring托管
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
/**
* 自动填充时间
* @param metaObject
*/
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill ....");
//插入时填充 create_time、update_time时间
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill ....");
//修改时 填充update_time时间
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
和删除的方法一样 就不过多叙述
什么是乐观锁?
乐观锁是相对悲观锁而言的,乐观锁假设数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则返回给用户错误的信息,让用户决定如何去做。
简单来说,就是 比较乐观,认为程序是不会出毛病的,如果出毛病了 就进行解决
而悲观锁与其相反,悲观锁在做任何事的时候,都会提前检查,这样虽然提高了安全性,但使效率大大降低
实现乐观锁
//添加注解 告诉系统 这是一个乐观锁
@Version
private Integer version;
package com.llf.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
//打开事务管理 即事务回滚之类的操作
@EnableTransactionManagement
// 告诉springBoot 这是spring配置类
@Configuration
public class MybatisplusConfig {
/**
乐观锁: OptimisticLockerInnerInterceptor
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
//乐观锁成功测试
// 所谓成功,就是对象A查询数据库后,拿到Version 在执行更新操作的时候 将拿到的version与此时数据库中对应的version进行对比,刚好一致 因此 就成功了
@Test
public void text2(){
User user = userMapper.selectById(1l);
user.setId(11L);
user.setName("过");
userMapper.updateById(user);
}
//乐观锁失败测试
// 所谓失败,就是一个对象A查询完数据库后,在提交更新操作之前,另一个对象B也查询了数据库,并完成了更新操作,这时数据库中的version是A查询的version+1,这显然与A查询的version不相等 所以就失败了
@Test
public void text3(){
User user = userMapper.selectById(1l);
user.setId(2L);
user.setName("杨过");
User user2 = userMapper.selectById(1l);
user.setId(2L);
user.setName("杨过");
userMapper.updateById(user2);
userMapper.updateById(user);
}
Mybatis-plus为我们准备了比PageHelper更为方便的分页插件
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,
* 需要设置 MybatisConfiguration#useDeprecatedExecutor = false
* 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor1() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}
将其放在 乐观锁的config配置文件中
因为同属于MybatisPlus配置文件
//分页查寻
@Test
public void text7(){
//第1页 显示3个 第一个参数是Current 第二个参数是Size
Page<User> page = new Page<>(1,3);
userMapper.selectPage(page,null);
//records 总记录
List<User> userList = page.getRecords();
for (User user : userList) {
System.out.println(user);
}
long size = page.getSize();
System.out.println("页面显示大小"+size);
long total = page.getTotal();
System.out.println("总数量"+total);
long current = page.getCurrent();
System.out.println("当前页码"+current);
long pages = page.getPages();
System.out.println("总页数"+pages);
}
和PageHelper一样 在查询之前 横切了一个count(*)的查询 来查询total
在 查询后自动添加limit 分页查询 得到结果
总记录:records
页面显示大小":size
总数量":total 总记录是一个集合 总数量是一个值
当前页码":current
"总页数":pages
条件构造器就好比是一个能够自动帮你拼接sql的工具,按照约定大于配置
的理念,我们只需要在合适的地方填入合适的参数,条件构造器就能帮我们完成复杂查询、子查询等操作
https://mp.baomidou.com/guide/wrapper.html#select
官方提供了许多接口供我们使用,且每一个接口的使用、参数说明都讲的很清楚
测试
@Test
public void test1(){
/*
模糊查询 查询名字里有狂字的所有人
查询操作 就创建QueryWrapper<>()
对应的 什么操作 就创建什么操作的Wrapper
*/
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.like("name","狂");
//如果查询一个人 就使用selectOne() 这样效率更快
List<Object> list = userMapper.selectObjs(wrapper);
for (Object o : list) {
System.out.println(o);
}
}
@Test
void test2(){
//查询eamil以T开头的人
QueryWrapper<User> wrapper = new QueryWrapper<>();
//以xxx开头 就是xx% 也就是likeRight
//以xxx结尾 就是%xxx 也就是likeLeft
wrapper.likeRight("email","t");
List<Object> list = userMapper.selectObjs(wrapper);
for (Object o : list) {
System.out.println(o);
}
}
@Test
void test3(){
//查询名字不为空的人
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.isNotNull("name");
List<Object> objects = userMapper.selectObjs(wrapper);
for (Object object : objects) {
System.out.println(object);
}
}
更多的例子 可以参考官方例子
代码生成器 也就是我们常说的逆向工程 他可以帮助我们自动生成底层的代码框架。Pojo、Mapper、service、Controller
且支持自动生成Swagger2API注解 乐观锁、自动填充等等
MyBatis-Plus 从 3.0.3
之后移除了代码生成器与模板引擎的默认依赖,需要手动添加相关依赖
<!-- 代码生成器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<!-- 引擎模板-->
<!-- https://mvnrepository.com/artifact/org.apache.velocity/velocity-engine-core -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
<!-- freemarker-->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
代码
package com.llf;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class MybatisPlusCode {
/**
* <p>
* 读取控制台内容
* </p>
*/
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("请输入" + tip + ":");
System.out.println(help.toString());
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StringUtils.isNotBlank(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("请输入正确的" + tip + "!");
}
public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
/**
全局配置
*/
GlobalConfig gc = new GlobalConfig();
//扫描当前路径
String projectPath = System.getProperty("user.dir");
//代码生成在/src/main/java目录下
gc.setOutputDir(projectPath + "/src/main/java");
//作者名字
gc.setAuthor("llf");
//是否打开生成后的文件夹
gc.setOpen(false);
//实体属性 Swagger2 注解
gc.setSwagger2(true);
mpg.setGlobalConfig(gc);
/**
*
/ 数据源配置
*
*/
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/mybatis-plus? useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("123456");
//将数据源仍进代码生成器
mpg.setDataSource(dsc);
/**
* 包配置
*/
PackageConfig pc = new PackageConfig();
// 模块名
pc.setModuleName(scanner("模块名"));
//项目包结构 例如com.llf.xxx
pc.setParent("com.llf");
//实体类包名
pc.setEntity("Pojo");
//Mapper包名
pc.setMapper("Mapper");
//Service包名
pc.setService("Service");
//去掉service的前缀
gc.setServiceName("%sService");
//ServiceImpl包名
pc.setServiceImpl("ServiceImpl");
//Mapperxml包名
pc.setXml("Mapperxml");
//将包结构设置仍进生成器
mpg.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
// 如果模板引擎是 freemarker
String templatePath = "/templates/mapper.xml.ftl";
// 如果模板引擎是 velocity
// String templatePath = "/templates/mapper.xml.vm";
// 自定义输出配置
List<FileOutConfig> focList = new ArrayList<>();
// 自定义配置会被优先输出
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
/*
cfg.setFileCreate(new IFileCreate() {
@Override
public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
// 判断自定义文件夹是否需要创建
checkDir("调用默认方法创建的目录,自定义目录用");
if (fileType == FileType.MAPPER) {
// 已经生成 mapper 文件判断存在,不想重新生成返回 false
return !new File(filePath).exists();
}
// 允许生成模板文件
return true;
}
});
*/
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
// 配置模板
TemplateConfig templateConfig = new TemplateConfig();
// 配置自定义输出模板
//指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
// templateConfig.setEntity("templates/entity2.java");
// templateConfig.setService();
// templateConfig.setController();
templateConfig.setXml(null);
mpg.setTemplate(templateConfig);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
//包名类名驼峰自动转换
strategy.setNaming(NamingStrategy.underline_to_camel);
//数据库字段驼峰自动转换
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
//实体类字段Lambok
strategy.setEntityLombokModel(true);
//Controller自动restful风格
strategy.setRestControllerStyle(true);
strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix(pc.getModuleName() + "_");
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
}
问题注意
为什么JPA不能使用?
JPA提示的方式需要根据Mapper找到实体类, 找到实体类有以下五种方式
@Entity com.xx.xx.UserModel
为什么生成的表名和期望的表名不一致
JPA提示生成代码, 按照以下规则找到表名
@Table(name="t_user")
@TableName("t_user")
@TableName com.xx.xx.UserModel
如果觉得这样子配置很麻烦,我们可以试试官方新出的MybatisX的插件 它简化了更多配置 可以说是安装即用
https://mp.baomidou.com/guide/mybatisx-idea-plugin.html
文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态
文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境
文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn
文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker
文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机
文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk
文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入
文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。 Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。
文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动
文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计
文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;gt;Jni-&amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图
文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法