首页
轻听2.0常见问题
轻听APP2.0
关于
Search
1
GO程序打包至Linux服务器运行
1,444 阅读
2
SpringBoot2.7.9+Mybatis-Plus3.5.3.1+ShardingSphere-JDBC5.3.1实现分库分表
858 阅读
3
Xmind 思维脑图软件破解版
848 阅读
4
完美解决方案-雪花算法ID到前端之后精度丢失问题
761 阅读
5
mysql 让清空表且自增的id重新从0开始的命令
659 阅读
Git
Java
SQL
区块链
网站搭建技术
SpringBoot
thymeleaf
Vue
GO
实用软件
登录
Search
canace
累计撰写
23
篇文章
累计收到
0
条评论
首页
栏目
Git
Java
SQL
区块链
网站搭建技术
SpringBoot
thymeleaf
Vue
GO
实用软件
页面
轻听2.0常见问题
轻听APP2.0
关于
搜索到
23
篇与
canace
的结果
2023-03-22
SpringBoot2.7.9+Mybatis-Plus3.5.3.1+ShardingSphere-JDBC5.3.1实现分库分表
ShardingSphere-JDBC采用Docker实现主从复制实现新增主节点配置文件mkdir -p /wolfcode/mysql/write_db/conf vi /wolfcode/mysql/write_db/conf/my.cnf #新增内容如下 [mysqld] #服务器唯一id,注意在集群中不要出现一样的 server-id=1 binlog_format=STATEMENT log-bin=master-bin log-bin-index=master-bin.index启动MySQL主节点docker run -d --name write_db -p 3306:3306 \ -v /wolfcode/mysql/write_db/conf:/etc/mysql/conf.d \ -v /wolfcode/mysql/write_db/data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=root \ mysql进行master容器,登录mysqldocker exec -it write_db /bin/bash mysql -uroot -proot #查看主节点状态 show master status;在mysql内部创建slave同步账号-- 创建slave用户 create user 'slave_user'@'%'; -- 设置密码 alter user 'slave_user'@'%' identified with mysql_native_password by 'root'; -- 授予复制权限 grant replication slave on *.* to 'slave_user'@'%'; -- 刷新权限 flush privileges;从节点1配置信息#退出mysql和docker exit; exit; mkdir -p /wolfcode/mysql/read_db0/conf vi /wolfcode/mysql/read_db0/conf/my.cnf #新增内容如下 [mysqld] #服务器唯一id,注意在集群中不要出现一样的 server-id=2 relay-log-index=slave-relay-bin.index relay-log=slave-replay-bin #启动从节点1 docker run -d --name read_db0 -p 3307:3306 \ -v /wolfcode/mysql/read_db0/conf:/etc/mysql/conf.d \ -v /wolfcode/mysql/read_db0/data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=root \ mysql #进入从节点容器,并登录mysql docker exec -it read_db0 /bin/bash mysql -uroot -proot #进入mysql执行命令 #docker inspect -f '{{.Name}} => {{.NetworkSettings.IPAddress }}' $(docker ps -aq) 查看ip change master to master_host='172.17.0.2', master_user='slave_user', master_password='root', master_port=3306, master_log_file='master-bin.000004', master_log_pos=156; #启动从节点1并查看状态 start slave; show slave status \G # Slave_IO_Running: Yes Slave_SQL_Running: Yes从节点2配置信息#退出mysql和docker exit; exit; mkdir -p /wolfcode/mysql/read_db1/conf vi /wolfcode/mysql/read_db1/conf/my.cnf #新增内容如下 [mysqld] #服务器唯一id,注意在集群中不要出现一样的 server-id=3 relay-log-index=slave-relay-bin.index relay-log=slave-replay-bin #启动从节点2 docker run -d --name read_db1 -p 3308:3306 \ -v /wolfcode/mysql/read_db1/conf:/etc/mysql/conf.d \ -v /wolfcode/mysql/read_db1/data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=root \ mysql #进入从节点容器,并登录mysql docker exec -it read_db1 /bin/bash mysql -uroot -proot #进入mysql执行命令 #docker inspect -f '{{.Name}} => {{.NetworkSettings.IPAddress }}' $(docker ps -aq) 查看ip #show master logs; 查看主节点log日志名 change master to master_host='172.17.0.2', master_user='slave_user', master_password='root', master_port=3306, master_log_file='master-bin.000004', master_log_pos=156; #启动从节点2并查看状态 start slave; show slave status \G # Slave_IO_Running: Yes Slave_SQL_Running: Yes创建完成后连接三个数据库,主表的变化,从表都会进行更新 --> Ip地址相同,端口不同3306,3307,3308使用ShardingSphere-JDBC(springboot框架)引入maven依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>shardingsphere-jdbc-core</artifactId> <version>5.3.1</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.5.3.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.27</version> </dependency> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.28</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.yaml</groupId> <artifactId>snakeyaml</artifactId> <version>1.33</version> </dependency>配置#在resources目录下新建sharding.yaml #数据源配置 dataSources: write_db: dataSourceClassName: com.zaxxer.hikari.HikariDataSource driverClassName: com.mysql.jdbc.Driver jdbcUrl: jdbc:mysql://192.168.31.128:3306/db_user?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true username: root password: root read_db0: dataSourceClassName: com.zaxxer.hikari.HikariDataSource driverClassName: com.mysql.jdbc.Driver jdbcUrl: jdbc:mysql://192.168.31.128:3307/db_user?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true username: root password: root read_db1: dataSourceClassName: com.zaxxer.hikari.HikariDataSource driverClassName: com.mysql.jdbc.Driver jdbcUrl: jdbc:mysql://192.168.31.128:3308/db_user?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true username: root password: root rules: # 读写分离 - !READWRITE_SPLITTING dataSources: readwrite_ds: staticStrategy: writeDataSourceName: write_db readDataSourceNames: - read_db0 - read_db1 loadBalancerName: random #负载均衡 loadBalancers: random: type: RANDOM #显示sql日志 props: sql-show: true #application.yml spring: datasource: driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver url: jdbc:shardingsphere:classpath:sharding.yamltest下新建一个Generator.java,用于mybatis-plus 代码生成public class Generator { @Test void generatorDomain() { FastAutoGenerator.create("jdbc:mysql://192.168.31.128:3306/db_user?serverTimezone=UTC&useSSL=false", "root", "root") .globalConfig(builder -> { builder.author("canace") // 设置作者 // .enableSwagger(f) // 开启 swagger 模式 .fileOverride() // 覆盖已生成文件 .outputDir("F:\\JavaFile\\ShardingSphereJDBC\\src\\main\\java"); // 指定输出目录 }) .packageConfig(builder -> { builder.parent("com.study.shardingspherejdbc") // 设置父包名 .moduleName(null) // 设置父包模块名 .pathInfo(Collections.singletonMap(OutputFile.xml, "F:\\JavaFile\\ShardingSphereJDBC\\src\\main\\resources")); // 设置mapperXml生成路径 }) .strategyConfig(builder -> { builder.addInclude("sys_user") // 设置需要生成的表名 .addTablePrefix("t_", "c_"); // 设置过滤表前缀 }) .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板 .execute(); } }springboot启动类上加mybatis-plus注解@SpringBootApplication @MapperScan("com.study.shardingspherejdbc.mapper") public class ShardingSphereJdbcApplication { public static void main(String[] args) { SpringApplication.run(ShardingSphereJdbcApplication.class, args); } }test文件内测试 @Autowired private ISysUserService iSysUserService; /** * 插入数据测试,三个数据库都保存了该数据 */ @Test void testInsert() { SysUser sysUser = new SysUser(); sysUser.setLoginName("canace1"); sysUser.setUserName("admin"); sysUser.setPhoneName("12345678999"); sysUser.setPassword("123456"); sysUser.setSalt("1234"); iSysUserService.save(sysUser); } /** * 读取测试,数据从两个读数据库中随机读取 */ @Test void testRead(){ for (int i = 0; i < 5; i++) { List<SysUser> sysUsers = iSysUserService.list(); sysUsers.forEach(System.out::println); System.out.println("=========================="); } }事务情况测试 /** * 没有使用事务测试,存入写数据库write_db,从读数据中读取 */ @Test void testNoTransactional() { SysUser sysUser = new SysUser(); sysUser.setLoginName("canace2"); sysUser.setUserName("admin2"); sysUser.setPhoneName("12345678999"); sysUser.setPassword("123456"); sysUser.setSalt("1234"); iSysUserService.save(sysUser); System.out.println("=========================="); List<SysUser> sysUsers = iSysUserService.list(); sysUsers.forEach(System.out::println); } /** * 使用事务测试,该数据由于事务没有提交,没有存入到任何数据库 * 但是在读取时会从读数据库中读,并且读到该数据 * Actual SQL: write_db ::: SELECT id,login_name,user_name,phone_name,password,salt FROM sys_user */ @Test @Transactional void testTransactional() { SysUser sysUser = new SysUser(); sysUser.setLoginName("canace3"); sysUser.setUserName("admin3"); sysUser.setPhoneName("12345678999"); sysUser.setPassword("123456"); sysUser.setSalt("1234"); iSysUserService.save(sysUser); System.out.println("=========================="); List<SysUser> sysUsers = iSysUserService.list(); sysUsers.forEach(System.out::println); }负载均衡策略配置rules: # 读写分离 - !READWRITE_SPLITTING dataSources: readwrite_ds: staticStrategy: writeDataSourceName: write_db readDataSourceNames: - read_db0 - read_db1 #负载均衡算法名称 loadBalancerName: weight # loadBalancerName: random # loadBalancerName: round_robin # 负载均衡算法配置 loadBalancers: weight: type: WEIGHT #权重 props: read_db0: 1 #两个读数据库进行1:2的权重进行读取 read_db1: 2 # round_robin: # type: ROUND_ROBIN #轮转 # props: # transaction-read-query-strategy: FIXED_PRIMARY #transaction-read-query-strategy说明:所以策略都有这个,事务内读请求路由策略,可选值:FIXED_PRIMARY(路由到 primary)、FIXED_REPLICA(根据随机策略选择一个固定的 replica)、DYNAMIC_REPLICA(根据随机策略路由到不同的 replica),默认值:FIXED_PRIMARY。 # random: # type: RANDOM #随机轮转负载均衡算法(ROUND_ROBIN)随即负载均衡算法(RANDOM)权重负载均衡算法(WEIGHT)分库分表实现创建新容器docker run -d \ -p 3309:3306 \ -v /wolfcode/mysql/customer_data0/conf:/etc/mysql/conf.d \ -v /wolfcode/mysql/customer_data0/data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=root \ --name customer_data0 \ mysql #进入从节点容器,并登录mysql docker exec -it customer_data0 /bin/bash mysql -uroot -proot创建数据库create database customer_data; use customer_data; CREATE TABLE `bus_statement` ( `statement_no` bigint(0) NOT NULL AUTO_INCREMENT, `customer_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, `customer_phone` bigint(0) NULL DEFAULT NULL, `actual_arrival_time` datetime(0) NULL DEFAULT NULL, `service_type` bigint(0) NULL DEFAULT NULL, `status` int(255) UNSIGNED ZEROFILL NULL DEFAULT NULL, `total_amount` decimal(10, 0) NULL DEFAULT NULL, `create_time` datetime(0) NULL DEFAULT NULL, `info` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, PRIMARY KEY (`statement_no`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;生成bus_satatement相关代码 @Test void generatorDomain() { FastAutoGenerator.create("jdbc:mysql://192.168.31.128:3309/customer_data?serverTimezone=UTC&useSSL=false", "root", "root") .globalConfig(builder -> { builder.author("canace") // 设置作者 // .enableSwagger(f) // 开启 swagger 模式 .fileOverride() // 覆盖已生成文件 .outputDir("F:\\JavaFile\\ShardingSphereJDBC\\src\\main\\java"); // 指定输出目录 }) .packageConfig(builder -> { builder.parent("com.study.shardingspherejdbc") // 设置父包名 .moduleName(null) // 设置父包模块名 .pathInfo(Collections.singletonMap(OutputFile.xml, "F:\\JavaFile\\ShardingSphereJDBC\\src\\main\\resources\\mapper")); // 设置mapperXml生成路径 }) .strategyConfig(builder -> { builder.addInclude("bus_statement") // 设置需要生成的表名 .addTablePrefix("t_", "c_"); // 设置过滤表前缀 }) .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板 .execute(); }新增yaml信息 customer_data0: dataSourceClassName: com.zaxxer.hikari.HikariDataSource driverClassName: com.mysql.jdbc.Driver jdbcUrl: jdbc:mysql://192.168.31.128:3309/customer_data?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true username: root password: root #进行分片 - !SHARDING tables: bus_statement: #表名 actualDataNodes: customer_data0.bus_statement # 由数据源名 + 表名组成(参考 Inline 语法规则)垂直分表 /** * 测试垂直分表,两个不同的表正确插入自己的表中 */ @Test void testVerticalShardingWrite(){ SysUser sysUser = new SysUser(); sysUser.setLoginName("canace4"); sysUser.setUserName("admin4"); sysUser.setPhoneName("12345678999"); sysUser.setPassword("123456"); sysUser.setSalt("1234"); iSysUserService.save(sysUser); BusStatement busStatement = new BusStatement(); busStatement.setCustomerName("canace"); busStatement.setCustomerPhone(12345678888L); busStatement.setActualArrivalTime(new Date()); busStatement.setCreateTime(new Date()); busStatement.setServiceType(0L); busStatement.setTotalAmount(new BigDecimal(588)); busStatement.setInfo("无"); iBusStatementService.save(busStatement); }分布式序列ID现在的服务基本是分布式、微服务形式的,而且大数据量也导致分库分表的产生,对于水平分表就需要保证表中 id 的全局唯一性。对于 MySQL 而言,一个表中的主键 id 一般使用自增的方式,但是如果进行水平分表之后,多个表中会生成重复的 id 值。那么如何保证水平分表后的多张表中的 id 是全局唯一性的呢?雪花算法是其中一个用于解决分布式 id 的高效方案,也是许多互联网公司在推荐使用的。#进行分片 - !SHARDING tables: bus_statement: #表名 actualDataNodes: customer_data0.bus_statement # 由数据源名 + 表名组成(参考 Inline 语法规则) keyGenerateStrategy: #分布式序列策略 column: statement_no # 自增列名称,缺省表示不使用自增主键生成器 keyGeneratorName: snowflake # 分布式序列算法名称 雪花算法 keyGenerators: snowflake: type: SNOWFLAKE /** * 测试雪花算法 */ @Test void testSnowFlake(){ BusStatement busStatement = new BusStatement(); busStatement.setCustomerName("canace2"); busStatement.setCustomerPhone(12345678888L); busStatement.setActualArrivalTime(new Date()); busStatement.setCreateTime(new Date()); busStatement.setServiceType(0L); busStatement.setTotalAmount(new BigDecimal(588)); busStatement.setInfo("无"); iBusStatementService.save(busStatement); }水平分表复制表bus_statement为bus_statement1,之前表改为bus_statement0#进行分片 - !SHARDING tables: bus_statement: #表名 # actualDataNodes: customer_data0.bus_statement # 由数据源名 + 表名组成(参考 Inline 语法规则) actualDataNodes: customer_data0.bus_statement$->{0..1} #支持多表,即bus_statement0和bus_statement1 tableStrategy: # 分表策略,同分库策略 standard: # 用于单分片键的标准分片场景 shardingColumn: statement_no # 分表列名称 shardingAlgorithmName: t_mod # 分表算法名称 keyGenerateStrategy: #分布式序列策略 column: statement_no # 自增列名称,缺省表示不使用自增主键生成器 keyGeneratorName: snowflake # 分布式序列算法名称 雪花算法 # 分片算法配置 shardingAlgorithms: t_mod: type: MOD props: sharding-count: 2 keyGenerators: snowflake: type: SNOWFLAKE /** * 水平分表测试 */ @Test void testTableShardingInsert(){ for (int i = 0; i < 15; i++) { BusStatement busStatement = new BusStatement(); busStatement.setCustomerName("canace2"+ i); busStatement.setCustomerPhone(12345678888L); busStatement.setActualArrivalTime(new Date()); busStatement.setCreateTime(new Date()); busStatement.setServiceType(0L); busStatement.setTotalAmount(new BigDecimal(588)); busStatement.setInfo("无"); iBusStatementService.save(busStatement); } } /** * 水平分表测试数据是否都查询出来了 */ @Test void testTableShardingRead(){ List<BusStatement> list = iBusStatementService.list(); list.forEach(System.out::println); }水平分库创建新容器docker run -d \ -p 3310:3306 \ -v /wolfcode/mysql/customer_data1/conf:/etc/mysql/conf.d \ -v /wolfcode/mysql/customer_data1/data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=root \ --name customer_data1 \ mysql创建表create database customer_data; use customer_data; CREATE TABLE `bus_statement0` ( `statement_no` bigint(0) NOT NULL AUTO_INCREMENT, `customer_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, `customer_phone` bigint(0) NULL DEFAULT NULL, `actual_arrival_time` datetime(0) NULL DEFAULT NULL, `service_type` bigint(0) NULL DEFAULT NULL, `status` int(255) UNSIGNED ZEROFILL NULL DEFAULT NULL, `total_amount` decimal(10, 0) NULL DEFAULT NULL, `create_time` datetime(0) NULL DEFAULT NULL, `info` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, PRIMARY KEY (`statement_no`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; CREATE TABLE `bus_statement1` ( `statement_no` bigint(0) NOT NULL AUTO_INCREMENT, `customer_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, `customer_phone` bigint(0) NULL DEFAULT NULL, `actual_arrival_time` datetime(0) NULL DEFAULT NULL, `service_type` bigint(0) NULL DEFAULT NULL, `status` int(255) UNSIGNED ZEROFILL NULL DEFAULT NULL, `total_amount` decimal(10, 0) NULL DEFAULT NULL, `create_time` datetime(0) NULL DEFAULT NULL, `info` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, PRIMARY KEY (`statement_no`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;配置 customer_data1: dataSourceClassName: com.zaxxer.hikari.HikariDataSource driverClassName: com.mysql.jdbc.Driver jdbcUrl: jdbc:mysql://192.168.31.128:3310/customer_data?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true username: root password: root #进行分片 - !SHARDING tables: bus_statement: #表名 # actualDataNodes: customer_data0.bus_statement # 由数据源名 + 表名组成(参考 Inline 语法规则) actualDataNodes: customer_data$->{0..1}.bus_statement$->{0..1} #支持多表,即bus_statement0和bus_statement1 tableStrategy: # 分表策略 standard: # 用于单分表键的标准分表场景 shardingColumn: statement_no # 分表列名称 shardingAlgorithmName: t_mod # 分表算法名称 databaseStrategy: #分库策略 standard: # 用于单分片键的标准分片场景 shardingColumn: customer_phone # 分片列名称 shardingAlgorithmName: t_inline # 分片算法名称 keyGenerateStrategy: #分布式序列策略 column: statement_no # 自增列名称,缺省表示不使用自增主键生成器 keyGeneratorName: snowflake # 分布式序列算法名称 雪花算法 # 分片算法配置 shardingAlgorithms: t_mod: type: MOD props: sharding-count: 2 t_inline: type: INLINE props: algorithm-expression: customer_data$->{customer_phone % 2} keyGenerators: snowflake: type: SNOWFLAKE /** * 水平分片测试,查看是否按照手机号码将数据分片到两个数据库中 */ @Test void testDatabaseShardingInsert(){ for (int i = 0; i < 5; i++) { BusStatement busStatement = new BusStatement(); busStatement.setCustomerName("canace"+ i); busStatement.setCustomerPhone(12345678888L); busStatement.setActualArrivalTime(new Date()); busStatement.setCreateTime(new Date()); busStatement.setServiceType(0L); busStatement.setTotalAmount(new BigDecimal(588)); busStatement.setInfo("无"); iBusStatementService.save(busStatement); } for (int i = 0; i < 10; i++) { BusStatement busStatement = new BusStatement(); busStatement.setCustomerName("dddd"+ i); busStatement.setCustomerPhone(99999999999L); busStatement.setActualArrivalTime(new Date()); busStatement.setCreateTime(new Date()); busStatement.setServiceType(0L); busStatement.setTotalAmount(new BigDecimal(688)); busStatement.setInfo("无"); iBusStatementService.save(busStatement); } } /** * 查看两个库两张表数据都查出来了 */ @Test void testDatabaseShardingRead(){ List<BusStatement> list = iBusStatementService.list(); list.forEach(System.out::println); }分片算法自动分片算法取模分片算法 MOD哈希取模分片算法 HASH_MOD基于分片容量的范围分片算法 VOLUME_RANGE基于分片边界的范围分片算法 BOUNDARY_RANGE自动时间段分片算法 AUTO_INTERVAL标准分片算法行表达式分片算法 INLINE时间范围分片算法 INTERVAL基于Cosld的固定时间范围的分片算法 COSID_INTERVAL基于Cosld的雪花ID固定时间范围的分片算法 COSID_INTERVAL_SNOWFLAKE基于Cosld的取模分片算法 COSID_MOD复合分片算法 COMPLEX_INLINEHint分片算法 HINT_INLINE自定义类分片算法详见:https://shardingsphere.apache.org/document/current/cn/user-manual/common-config/builtin-algorithm/sharding
2023年03月22日
858 阅读
0 评论
0 点赞
2023-03-03
Java基础
Java快速入门Java基础语法Java基础语法类型转换运算符键盘录入技术程序流程控制程序流程控制是控制代码怎么去执行的顺序结构代码按照顺便正常执行分支结构循环结构跳转关键字(break,continue)随机数Random类数组作用一个容器,用于在程序中存储一批同种类型的数据定义遍历常见问题方法作用封装一段代码的语法结构,可以被重复调用,以此提高代码的复用性,提高开发效率,让程序逻辑更清晰定义格式修饰符 返回值类型 方法名(形参列表){ 方法体代码(需要执行的功能代码) return 返回值; } //如果方法没有返回结果,返回值类型申明为:void //方法需要调用才能执行注意事项方法重载return跳出并立即结束当前方法的执行面向对象编程(oop)定义(思想)java 万物皆对象创建对象构造器this关键字封装常用API(String、ArrayList)StringArrayListstatic饿汉单例代码示例:/** 使用饿汉单例实现单例类 */ public class SingleInstance { /** 2、饿汉单例是在获取对象前,对象已经提前准备好了一个。 这个对象只能是一个,所以定义静态成员变量记住。 */ public static SingleInstance instance = new SingleInstance(); /** 1、必须把构造器私有化。 */ private SingleInstance(){ } }懒汉单例代码示例:/** 懒汉单例 */ public class SingleInstance2 { /** 2、定义一个静态的成员变量负责存储一个对象。 只加载一次,只有一份。 注意:最好私有化,这样可以避免给别人挖坑! */ private static SingleInstance2 instance; /** 3、提供一个方法,对外返回单例对象。 */ public static SingleInstance2 getInstance() { if(instance == null){ // 第一次来拿对象 :此时需要创建对象。 instance = new SingleInstance2(); } return instance; } /** 1、私有化构造器 */ private SingleInstance2(){ } } 继承权限修饰符final常量枚举抽象类接口多态定义多态是同一个行为具有不同的表现形式或形态的能力同一方法可以根据发送对象的不同而采用不同的行为方式多态就是事物的多种形态,一个对象在不同条件下所表现的不同形式存在条件继承或实现:在多态中必须存在有继承或实现关系的子类和父类方法的重写:子类对父类中的某些方法进行重新定义(重写,使用@Override注解进行重写)基类引用指向派生类对象,即父类引用指向子类对象,父类类型:指子类对象继承的父类类型,或实现的父接口类型格式父类类型 变量名 = new 子类类型(); 然后通过 变量名.方法名()调用在子类中重写的方法 多态体现为父类引用变量可以指向子类对象:定义了一个父类类型的引用,指向新建的子类类型的对象,由于子类是继承他的父类的,所以父类类型的引用是可以指向子类类型的对象的特点多态情况下,子类和父类存在同名的成员变量时,访问的时父类的成员变量多态情况下,子父类存在同名的非静态成员方法时,访问的是子类中重写的方法多态情况下,子父类存在同名的静态成员变量成员方法时,访问的是父类的成员函数多态情况下,不能访问子类独由的方法instanceof关键字格式变量名 instanceof 数据类型 //如果变量属于该数据类型或者其子类型,返回true //如果变量不属于该数据类或者其子类型,返回false代码示例 public class DemoApplication { public static void main(String[] args) { //向上转型 //父类类型 对象 = new 子类类型() Animal animal = new Cat(); //向下转型 //子类类型 子类变量名 = (子类类型) 父类变量名 if ( animal instanceof Cat){ Cat cat = (Cat) animal; cat.sleep(); }else if(animal instanceof Dog){ Dog dog = (Dog) animal; dog.walk(); } } }集合数组的长度是固定的。集合的长度是可变的。数组中存储的是同一类型的元素,可以存储基本数据类型值。集合存储的都是对象。而且对象的类型可以不一致。在开发中一般当对象多的时候,使用集合进行存储。ColloctionColloction常用APIpublic boolean add(E e): 把给定的对象添加到当前集合中 。 public void clear():清空集合中所有的元素。 public boolean remove(E e): 把给定的对象在当前集合中删除。 public boolean contains(Object obj): 判断当前集合中是否包含给定的对象。 public boolean isEmpty(): 判断当前集合是否为空。 public int size(): 返回集合中元素的个数。 public Object[] toArray(): 把集合中的元素,存储到数组中Iterator 迭代器迭代:即Collection集合元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续在判断,如果还有就再取出出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。常用方法public E next():返回迭代的下一个元素。 public boolean hasNext():如果仍有元素可以迭代,则返回 true。代码示例public class IteratorDemo { public static void main(String[] args) { // 使用多态方式 创建对象 Collection<String> coll = new ArrayList<String>(); // 添加元素到集合 coll.add("串串星人"); coll.add("吐槽星人"); coll.add("汪星人"); //遍历 //使用迭代器 遍历 每个集合对象都有自己的迭代器 Iterator<String> it = coll.iterator(); // 泛型指的是 迭代出 元素的数据类型 while(it.hasNext()){ //判断是否有迭代元素 String s = it.next();//获取迭代出的元素 System.out.println(s); } } } //注意,如果集合没有元素使用迭代器的next的方法会java.util.NoSuchElementException没有集合元素的错误。删除元素常用在集合Collection的remove方法无法根据条件删除代码示例: @Test public void test02(){ Collection<String> coll = new ArrayList<>(); coll.add("陈琦"); coll.add("李晨"); coll.add("邓超"); coll.add("黄晓明"); //删除名字有三个字的 // coll.remove(o)//无法编写 Iterator<String> iterator = coll.iterator(); while(iterator.hasNext()){ String element = iterator.next(); if(element.length()==3){ // coll.remove(element);//错误的 iterator.remove(); } } System.out.println(coll); } 增强for示例:for(元素的数据类型 变量 : Collection集合or数组){ //写操作代码 }List特点List集合所有的元素是以一种线性方式进行存储的,例如,存元素的顺序是11、22、33。那么集合中,元素的存储就是按照11、22、33的顺序完成的)它是一个元素存取有序的集合。即元素的存入顺序和取出顺序一致。它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)。集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素。常用方法1.添加元素 void add(int index, E ele) boolean addAll(int index, Collection<? extends E> eles) 2、获取元素 E get(int index) List subList(int fromIndex, int toIndex) 3、获取元素索引 int indexOf(Object obj) int lastIndexOf(Object obj) 4、删除和替换元素 E remove(int index) E set(int index, E ele)实现类ArrayList集合java.util.ArrayList集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList是最常用的集合。代码示例class Example2{ public static void main(String[] args) { ArrayList arrayList = new ArrayList(); arrayList.add("a"); arrayList.add("b"); arrayList.add("c"); System.out.println("arrayList的元素为:"+arrayList); arrayList.set(0,"c"); //将索引为0的位置对象a修改为对象c System.out.println("arrayList的元素为"+arrayList); arrayList.add(1,"e"); //将对象e添加到索引为1的位置 System.out.print("arrayList的元素为:"); for (int i=0;i<arrayList.size();i++){ System.out.print(arrayList.get(i));//for循环迭代arrayList集合元素 } System.out.println(""); System.out.println("arrayList指定元素c位置的索引为"+arrayList.indexOf("c")); //返回列表中指定元素c位置的索引 System.out.println("arrayList指定元素c最后位置的索引为"+arrayList.lastIndexOf("c")); //返回列表中指定元素c最后位置的索引 System.out.println("arrayList的指定区域为"+arrayList.subList(1,2)); //返回列表中指返回一个指定区域的List集合对象[1,2) } }LinkedList集合java.util.LinkedList集合数据存储的结构是链表结构(双链表)。方便元素添加、删除的集合。代码示例public class Example3 { public static void main(String[] args) { LinkedList linkedList = new LinkedList(); linkedList.add("a"); linkedList.add("b"); linkedList.add("c"); linkedList.add("d"); //获得并输入列表开头的对象 System.out.println("列表开头元素为:"+linkedList.getFirst()+"列表结尾元素为:"+linkedList.getLast()); linkedList.addFirst("rr"); //向列表开头添加一个对象 System.out.println("列表中所有元素:"+linkedList); linkedList.removeLast();//移除列表结尾元素 System.out.println("列表结尾元素为:"+linkedList.getLast()); //获取并输出列表结尾的对象 } }ListlteratorList 集合额外提供了一个 listIterator() 方法,该方法返回一个 ListIterator 对象, ListIterator 接口继承了 Iterator 接口,提供了专门操作 List 的方法:代码示例 public static void main(String[] args) { List<Student> c = new ArrayList<>(); c.add(new Student(1,"张三")); c.add(new Student(2,"李四")); c.add(new Student(3,"王五")); c.add(new Student(4,"赵六")); c.add(new Student(5,"钱七")); //从指定位置往前遍历 ListIterator<Student> listIterator = c.listIterator(c.size()); while(listIterator.hasPrevious()){ Student previous = listIterator.previous(); System.out.println(previous); } }Set特点特点:无序,不重复遍历:foreach,迭代器扩容: 初始容量16,负载因子0.75,扩容增量1倍实现类HsshSet特点它存储唯一元素并允许空值,依据对象的hashcode来确定该元素是否存在由HashMap支持不保持插入顺序(无序)非线程安全性能参数:初始容量,负载因子,默认值: 初始容量16,负载因子0.75,示例:new HashSet<>(20, 0.5f);注意HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取和查找性能。HashSet 集合判断两个元素相等的标准:两个对象通过 hashCode() 方法比较相等,并且两个对象的 equals() 方法返回值也相等。因此,存储到HashSet的元素要重写hashCode和equals方法。LinkedHashSetLinkedHashSet是HashSet的子类,它在HashSet的基础上,在结点中增加两个属性before和after维护了结点的前后添加顺序。java.util.LinkedHashSet,它是链表和哈希表组合的一个数据存储结构。LinkedHashSet插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。(保持插入顺序)TreeSet特点是一个包含有序的且没有重复元素的集合作用是提供有序的Set集合,自然排序或者根据提供的Comparator进行排序TreeSet是基于TreeMap实现的代码示例//演示两种自定义排序方法 //1. 较器通过构造函数传入比 TreeSet<Integer> tset = new TreeSet<Integer>(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { // TODO Auto-generated method stub return o2 - o1; } }); //2.对象类中定义 @Override public int compareTo(Student o) { if (this.getAge() - o.getAge() == 0) { return this.getSid() - o.getSid(); } return this.getAge() - o.getAge(); }Map概述现实生活中,我们常会看到这样的一种集合:IP地址与主机名,身份证号与个人,系统用户名与系统用户对象等,这种一一对应的关系,就叫做映射。Java提供了专门的集合类用来存放这种对象关系的对象,即java.util.Map<K,V>接口。我们通过查看Map接口描述,发现Map<K,V>接口下的集合与Collection<E>接口下的集合,它们存储数据的形式不同。Collection中的集合,元素是孤立存在的(理解为单身),向集合中存储元素采用一个个元素的方式存储。Map中的集合,元素是成对存在的(理解为夫妻)。每个元素由键与值两部分组成,通过键可以找对所对应的值。Collection中的集合称为单列集合,Map中的集合称为双列集合。需要注意的是,Map中的集合不能包含重复的键,值可以重复;每个键只能对应一个值(这个值可以是单个值,也可以是个数组或集合值)。常用APIpublic class MapDemo { public static void main(String[] args) { //创建 map对象 HashMap<String, String> map = new HashMap<String, String>(); //添加元素到集合 map.put("黄晓明", "杨颖"); map.put("文章", "马伊琍"); map.put("邓超", "孙俪"); System.out.println(map); //String remove(String key) System.out.println(map.remove("邓超")); System.out.println(map); // 想要查看 黄晓明的媳妇 是谁 System.out.println(map.get("黄晓明")); System.out.println(map.get("邓超")); } } //使用put方法时,若指定的键(key)在集合中没有,则没有这个键对应的值,返回null,并把指定的键值添加到集合中; //若指定的键(key)在集合中存在,则返回值为集合中键对应的值(该值为替换前的值),并把指定键所对应的值,替换成指定的新值。遍历public class TestMap { public static void main(String[] args) { HashMap<String,String> map = new HashMap<>(); map.put("许仙", "白娘子"); map.put("董永", "七仙女"); map.put("牛郎", "织女"); map.put("许仙", "小青"); //单独遍历key和值 System.out.println("所有的key:"); Set<String> keySet = map.keySet(); for (String key : keySet) { System.out.println(key); } System.out.println("所有的value:"); Collection<String> values = map.values(); for (String value : values) { System.out.println(value); } //同时遍历key-value entrySet() System.out.println("所有的映射关系"); Set<Map.Entry<String,String>> entrySet = map.entrySet(); for (Map.Entry<String,String> entry : entrySet) { System.out.println(entry.getKey()+"->"+entry.getValue()); } } } 实现类HashMapHashMap线程不安全,允许使用null键和null值;Hashtable是线程安全的,任何非 null 对象都可以用作键或值。LinkedHashMap维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序通常就是将键插入到映射中的顺序(插入顺序)。TreeMap基于红黑树(Red-Black tree)的 NavigableMap 实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。package com.atguigu.map; import java.util.Comparator; import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; import org.junit.Test; public class TestTreeMap { @Test public void test1() { TreeMap<String,Integer> map = new TreeMap<>(); map.put("Jack", 11000); map.put("Alice", 12000); map.put("zhangsan", 13000); map.put("baitao", 14000); map.put("Lucy", 15000); //String实现了Comparable接口,默认按照Unicode编码值排序 Set<Entry<String, Integer>> entrySet = map.entrySet(); for (Entry<String, Integer> entry : entrySet) { System.out.println(entry); } } @Test public void test2() { //指定定制比较器Comparator,按照Unicode编码值排序,但是忽略大小写 TreeMap<String,Integer> map = new TreeMap<>(new Comparator<String>() { @Override public int compare(String o1, String o2) { return o1.compareToIgnoreCase(o2); } }); map.put("Jack", 11000); map.put("Alice", 12000); map.put("zhangsan", 13000); map.put("baitao", 14000); map.put("Lucy", 15000); Set<Entry<String, Integer>> entrySet = map.entrySet(); for (Entry<String, Integer> entry : entrySet) { System.out.println(entry); } } }Collections工具类Collections 是一个操作 Set、List 和 Map 等集合的工具类。Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法:public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)在coll集合中找出最大的元素,集合中的对象必须是T或T的子类对象,而且支持自然排序 public static T max(Collection<? extends T> coll,Comparator<? super T> comp)在coll集合中找出最大的元素,集合中的对象必须是T或T的子类对象,按照比较器comp找出最大者 public static void reverse(List<?> list)反转指定列表List中元素的顺序。 public static void shuffle(List<?> list) List 集合元素进行随机排序,类似洗牌 public static <T extends Comparable<? super T>> void sort(List list)根据元素的自然顺序对指定 List 集合元素按升序排序 public static void sort(List list,Comparator<? super T> c)根据指定的 Comparator 产生的顺序对 List 集合元素进行排序 public static void swap(List<?> list,int i,int j)将指定 list 集合中的 i 处元素和 j 处元素进行交换 public static int frequency(Collection<?> c,Object o)返回指定集合中指定元素的出现次数 public static void copy(List<? super T> dest,List<? extends T> src)将src中的内容复制到dest中 public static boolean replaceAll(List list,T oldVal,T newVal):使用新值替换 List 对象的所有旧值StreamStream流是对集合(Collection)对象功能的增强,与Lambda表达式结合,可以提高编程效率、间接性和程序可读性。特点1、代码简洁:函数式编程写出的代码简洁且意图明确,使用stream接口让你从此告别for循环2、多核友好:Java函数式编程使得编写并行程序如此简单,就是调用一下方法流程创建流Stream创建Stream<Integer> stream1 = Stream.of(1,2,3,4,5);Collection集合创建(应用中最常用的一种)List<Integer> integerList = new ArrayList<>(); integerList.add(1); integerList.add(2); integerList.add(3); integerList.add(4); integerList.add(5); Stream<Integer> listStream = integerList.stream();Array数组创建int[] intArr = {1, 2, 3, 4, 5}; IntStream arrayStream = Arrays.stream(intArr);通过Arrays.stream方法生成流,并且该方法生成的流是数值流【即IntStream】而不是 Stream注:使用数值流可以避免计算过程中拆箱装箱,提高性能。Stream API提供了mapToInt、mapToDouble、mapToLong三种方式将对象流【即Stream 】转换成对应的数值流,同时提供了boxed方法将数值流转换为对象流文件创建try { Stream<String> fileStream = Files.lines(Paths.get("data.txt"), Charset.defaultCharset()); } catch (IOException e) { e.printStackTrace(); } //把流创建在try(){}的()里可以在结束时自动关闭该流通过Files.line方法得到一个流,并且得到的每个流是给定文件中的一行函数创建iteratorStream<Integer> iterateStream = Stream.iterate(0, n -> n + 2).limit(5);iterate方法接受两个参数,第一个为初始化值,第二个为进行的函数操作,因为iterator生成的流为无限流,通过limit方法对流进行了截断,只生成5个偶数 generatorStream<Double> generateStream = Stream.generate(Math::random).limit(5);generate方法接受一个参数,方法参数类型为Supplier ,由它为流提供值。generate生成的流也是无限流,因此通过limit对流进行了截断操作流中间操作符//1、filter:输出ID大于6的user对象(过滤) List<User> filetrUserList = userList.stream().filter(user -> user.getId() > 6).collect(Collectors.toList()); filetrUserList.forEach(System.out::println); //2、map List<String> mapUserList = userList.stream().map(user -> user.getName() + "用户").collect(Collectors.toList()); mapUserList.forEach(System.out::println); //3、distinct:去重 //User::getCity() 完全写法为:user -> user.getCity() List<String> distinctUsers = userList.stream().map(User::getCity).distinct().collect(Collectors.toList()); distinctUsers.forEach(System.out::println); //4、sorted:排序,根据名字倒序 userList.stream().sorted(Comparator.comparing(User::getName).reversed()).collect(Collectors.toList()).forEach(System.out::println); //5、limit:取前5条数据 userList.stream().limit(5).collect(Collectors.toList()).forEach(System.out::println); //6、skip:跳过第几条取后几条 userList.stream().skip(7).collect(Collectors.toList()).forEach(System.out::println); //7、flatMap:数据拆分一对多映射 userList.stream().flatMap(user -> Arrays.stream(user.getCity().split(","))).forEach(System.out::println); //8、peek:对元素进行遍历处理,每个用户ID加1输出 userList.stream().peek(user -> user.setId(user.getId()+1)).forEach(System.out::println);终端操作符//1、collect:收集器,将流转换为其他形式 Set set = userList.stream().collect(Collectors.toSet()); set.forEach(System.out::println); System.out.println("--------------------------"); List list = userList.stream().collect(Collectors.toList()); list.forEach(System.out::println); //2、forEach:遍历流 userList.stream().forEach(user -> System.out.println(user)); userList.stream().filter(user -> "上海".equals(user.getCity())).forEach(System.out::println); //3、findFirst:返回第一个元素 User firstUser = userList.stream().findFirst().get(); User firstUser1 = userList.stream().filter(user -> "上海".equals(user.getCity())).findFirst().get(); //4、findAny:将返回当前流中的任意元素 User findUser = userList.stream().findAny().get(); User findUser1 = userList.stream().filter(user -> "上海".equals(user.getCity())).findAny().get(); //5、count:返回流中元素总数 long count = userList.stream().filter(user -> user.getAge() > 20).count(); System.out.println(count); //6、sum:求和 int sum = userList.stream().mapToInt(User::getId).sum(); //7、max:最大值 int max = userList.stream().max(Comparator.comparingInt(User::getId)).get().getId(); //8、min:最小值 int min = userList.stream().min(Comparator.comparingInt(User::getId)).get().getId(); //9、anyMatch:检查是否至少匹配一个元素 boolean matchAny = userList.stream().anyMatch(user -> "北京".equals(user.getCity())); //10、allMatch:检查是否匹配所有元素 boolean matchAll = userList.stream().allMatch(user -> "北京".equals(user.getCity())); //11、noneMatch:检查是否没有匹配所有元素,返回boolean boolean nonaMatch = userList.stream().allMatch(user -> "云南".equals(user.getCity())); //12、reduce:将流中元素反复结合起来,得到一个值 Optional reduce = userList.stream().reduce((user, user2) -> { return user; }); if(reduce.isPresent()) System.out.println(reduce.get());Collect收集//1.toList() 将用户ID存放到List集合中 List<Integer> idList = userList.stream().map(User::getId).collect(Collectors.toList()) ; //2.toMap() 将用户ID和Name以Key-Value形式存放到Map集合中 Map<Integer,String> userMap = userList.stream().collect(Collectors.toMap(User::getId,User::getName)); //3.toSet() 将用户所在城市存放到Set集合中 Set<String> citySet = userList.stream().map(User::getCity).collect(Collectors.toSet()); //4.counting() 符合条件的用户总数 long count = userList.stream().filter(user -> user.getId()>1).collect(Collectors.counting()); //5.summingInt() 对结果元素即用户ID求和 Integer sumInt = userList.stream().filter(user -> user.getId()>2).collect(Collectors.summingInt(User::getId)) ; //6.minBy() 筛选元素中ID最小的用户 User maxId = userList.stream().collect(Collectors.minBy(Comparator.comparingInt(User::getId))).get() ; //7.joining() 将用户所在城市,以指定分隔符链接成字符串; String joinCity = userList.stream().map(User::getCity).collect(Collectors.joining("||")); //8.groupingBy() 按条件分组,以城市对用户进行分组; Map<String,List<User>> groupCity = userList.stream().collect(Collectors.groupingBy(User::getCity));异常try( //此处使用如stream流之类的需要使用后关闭的 ){ //此处使用正常的主体代码 }catch(Exception e){ //打印异常或写入日志 }finally{ //不管程序是否异常,这里都会执行 }File和IO流File对象创建File对象 public static void main(String[] args) { //创建一个File对象 并指定文件得路径 \转移字符串 //第一种Windows通用两种分隔符 File file01 = new File("D:\\AAA\\aaa.txt"); File file02 = new File("D:/AAA/bbb.txt"); // 第二种 File.separator根据当前代码所在得系统自动获取相应得分割符 System.out.println(File.separator); // \因为我们当前在window下 File file03 = new File("D:"+File.separator+"AAA"+File.separator+"ccc.txt");添加文件 //创建文件对象 File file = new File("F:/AAA/a.txt"); //添加文件操作 file.createNewFile(); File file2 = new File("F:/AAA/bbb"); file2.mkdir();//创建单层文件夹 File file3 = new File("F:/AAA/bbb/ccc"); file3.mkdirs();//创建多层文件夹删除操作 //创建文件对象 File file = new File("F:/AAA/a.txt"); //删除操作 file.delete();//删除文件,同时可以删除空的文件夹 file3.deleteOnExit();//程序退出时删除文件修改文件 //创建文件对象 File file = new File("F:/AAA/a.txt"); //修改操作 file.setReadable(false);//修改能否打开文件的权限 file.setWritable(false);//修改能否修改文件中的内容的权限 file.setReadOnly();//修改文件为只读 file.renameTo(new File("D:/AAA/aaa.txt"));//给文件重命名查询文件 //创建文件对象 File file = new File("F:/AAA/a.txt"); //查询操作 String name = file.getName();//获取文件名称 String parent = file.getParent();//获取父级的名称 String path = file.getPath();//获取路径 System.out.println(name + " "+ parent+" "+path); boolean f1 = file.isFile();//是否为文件类型 boolean f2 = file.isDirectory();//是否为文件夹类型 System.out.println(f1 + " "+f2);遍历public class test { public static void main(String[] args) { String[] s=new String[100]; File f=new File("D:/个人文件"); s=f.list(); //获取当前目录下所有的一级文件名称到一个字符串数组中返回 for(String ss:s){ System.out.println(ss); } File[] s1=new File[100]; File f1=new File("D:/个人文件"); s1=f1.listFiles();//获取当前目录下所有的一级文件对象到一个对象数组中返回(重点) for(File ss1:s1){ System.out.println(ss1); } } } IO流IO流即输入输出流,用于处理数据的传输字符集编码、解码操作字节流字节流基类字节输入流(InputStream) 常用方法: // 从输入流中读取数据的下一个字节 abstract int read() // 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b中 int read(byte[] b) // 将输入流中最多 len 个数据字节读入 byte 数组 int read(byte[] b, int off, int len) // 跳过和丢弃此输入流中数据的 n个字节 long skip(long n) // 关闭此输入流并释放与该流关联的所有系统资源 void close()字节输出流(OutputStream) 常用方法: // 将 b.length 个字节从指定的 byte 数组写入此输出流 void write(byte[] b) // 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流 void write(byte[] b, int off, int len) // 将指定的字节写入此输出流 abstract void write(int b) // 关闭此输出流并释放与此流有关的所有系统资源 void close() // 刷新此输出流并强制写出所有缓冲的输出字节 void flush()字节文件操作流字节文件输入流(FileInputStream) 构造方法: // 通过打开一个到实际文件的连接来创建一个FileInputStream,该文件通过文件系统中的File对象file指定 FileInputStream(File file) // 通过打开一个到实际文件的连接来创建一个FileInputStream,该文件通过文件系统中的路径name指定 FileInputStream(String name) //示例(使用字节数组) //构造方法 InputStream inputStream2 = new FileInputStream("f://hello/test.txt"); // 字节数组 byte[] b = new byte[2]; int i2 = 0; // 一次读取一个字节数组 while ((i2 = inputStream2.read(b)) != -1) { System.out.print(new String(b, 0, i2) + " ");// AB CD } //关闭IO流 inputStream2.close();字节文件输出流(FileOutputStream) 构造方法: // 创建一个向指定File对象表示的文件中写入数据的文件输出流 FileOutputStream(File file) // 创建一个向指定File对象表示的文件中写入数据的文件输出流 FileOutputStream(File file, boolean append) // 创建一个向具有指定名称的文件中写入数据的输出文件流 FileOutputStream(String name) // 创建一个向具有指定name的文件中写入数据的输出文件流 FileOutputStream(String name, boolean append) OutputStream outputStream = new FileOutputStream(new File("test.txt")); // 写出数据 outputStream.write("ABCD".getBytes()); // 关闭IO流 outputStream.close(); // 内容追加写入 OutputStream outputStream2 = new FileOutputStream("test.txt", true); // 输出换行符 outputStream2.write("\r\n".getBytes()); // 输出追加内容 outputStream2.write("hello".getBytes()); // 关闭IO流 outputStream2.close();字节缓冲流(高级流)字节缓存输入流(BufferedInputStream) 构造方法: // 创建一个 BufferedInputStream并保存其参数,即输入流in,以便将来使用。 BufferedInputStream(InputStream in) // 创建具有指定缓冲区大小的 BufferedInputStream并保存其参数,即输入流in以便将来使用 BufferedInputStream(InputStream in, int size) //示例 InputStream in = new FileInputStream("test.txt"); // 字节缓存流 BufferedInputStream bis = new BufferedInputStream(in); byte[] bs = new byte[20]; int len = 0; while ((len = bis.read(bs)) != -1) { System.out.print(new String(bs, 0, len)); } // 关闭流 bis.close();字节缓存输出流(BufferedOutputStream) 构造方法: // 创建一个新的缓冲输出流,以将数据写入指定的底层输出流 BufferedOutputStream(OutputStream out) // 创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流 BufferedOutputStream(OutputStream out, int size) 常用方法: // 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此缓冲的输出流 void write(byte[] b, int off, int len) // 将指定的字节写入此缓冲的输出流 void write(int b) // 刷新此缓冲的输出流 void flush() //示例 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("test.txt", true)); // 输出换行符 bos.write("\r\n".getBytes()); // 输出内容 bos.write("Hello Android".getBytes()); // 刷新此缓冲的输出流 bos.flush(); // 关闭流 bos.close();字符流字符流基类字符输入流(Reader) 常用方法: // 读取单个字符 int read() // 将字符读入数组 int read(char[] cbuf) // 将字符读入数组的某一部分 abstract int read(char[] cbuf, int off, int len) // 跳过字符 long skip(long n) // 关闭该流并释放与之关联的所有资源 abstract void close()字符输出流(Write) 常用方法: // 写入字符数组 void write(char[] cbuf) // 写入字符数组的某一部分 abstract void write(char[] cbuf, int off, int len) // 写入单个字符 void write(int c) // 写入字符串 void write(String str) // 写入字符串的某一部分 void write(String str, int off, int len) // 将指定字符添加到此 writer Writer append(char c) // 将指定字符序列添加到此 writer Writer append(CharSequence csq) // 将指定字符序列的子序列添加到此 writer.Appendable Writer append(CharSequence csq, int start, int end) // 关闭此流,但要先刷新它 abstract void close() // 刷新该流的缓冲 abstract void flush()字符转换流InputStreamReader(字节流转字符流) 构造方法: // 创建一个使用默认字符集的 InputStreamReader InputStreamReader(InputStream in) // 创建使用给定字符集的 InputStreamReader InputStreamReader(InputStream in, Charset cs) // 创建使用给定字符集解码器的 InputStreamReader InputStreamReader(InputStream in, CharsetDecoder dec) // 创建使用指定字符集的 InputStreamReader InputStreamReader(InputStream in, String charsetName) 特有方法: //返回此流使用的字符编码的名称 String getEncoding() //代码示例 //使用默认编码 InputStreamReader reader = new InputStreamReader(new FileInputStream("test.txt")); int len; while ((len = reader.read()) != -1) { System.out.print((char) len);//爱生活,爱Android } reader.close(); //指定编码 InputStreamReader reader = new InputStreamReader(new FileInputStream("test.txt"),"utf-8"); int len; while ((len = reader.read()) != -1) { System.out.print((char) len);//????????Android } reader.close();OutputStreamWriter(字节流转字符流) 构造方法: // 创建使用默认字符编码的 OutputStreamWriter OutputStreamWriter(OutputStream out) // 创建使用给定字符集的 OutputStreamWriter OutputStreamWriter(OutputStream out, Charset cs) // 创建使用给定字符集编码器的 OutputStreamWriter OutputStreamWriter(OutputStream out, CharsetEncoder enc) // 创建使用指定字符集的 OutputStreamWriter OutputStreamWriter(OutputStream out, String charsetName) 特有方法: //返回此流使用的字符编码的名称 String getEncoding() 字符缓冲流BufferedReader 构造方法: // 创建一个使用默认大小输入缓冲区的缓冲字符输入流 BufferedReader(Reader in) // 创建一个使用指定大小输入缓冲区的缓冲字符输入流 BufferedReader(Reader in, int sz) 特有方法: // 读取一个文本行 String readLine() //代码示例 //生成字符缓冲流对象 BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("test.txt"))); String str; //一次性读取一行 while ((str = reader.readLine()) != null) { System.out.println(str);// 爱生活,爱Android } //关闭流 reader.close();BufferedWriter 构造方法: // 创建一个使用默认大小输出缓冲区的缓冲字符输出流 BufferedWriter(Writer out) // 创建一个使用给定大小输出缓冲区的新缓冲字符输出流 BufferedWriter(Writer out, int sz) 特有方法: // 写入一个行分隔符 void newLine() 线程创建线程:方式一方式二匿名写法:方式三三种方式对比总结线程Thread常用方法、构造器线程安全问题原因:多个线程同时访问同一个共享资源且存在修改该资源解决方案:加锁,把共享资源进行上锁,每次只能一个线程进入访问完毕以后解锁,然后其他线程才能进来同步代码块:synchronized(同步锁对象){ 操作共享资源的代码(核心代码) }锁对象规范要求:同步方法:同步代码块与同步方法:同步代码块锁的范围更小,同步方法锁的范围更大。Lock锁:线程通信线程池(重点)定时器Timer定时器:本身是一个单线程ScheduledExecutorService定时器:多线程,基于线程池并发、并行并发:CPU分时轮询的执行线程并行:同一时刻同时在执行线程的生命周期网络编程(通信)实现网络编程关键的三要素IP端口号协议网络通信协议:连接和通信数据的规则UDP协议代码示例(默认支持多个客户端)//客户端 import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.util.Scanner; public class ClientDemo1 { public static void main(String[] args) throws Exception { //1.创建发送端对象:发送端自带默认的端口号(人) DatagramSocket socket = new DatagramSocket(); Scanner sc = new Scanner(System.in); while (true) { System.out.println("请输入发送的消息:"); String msg = sc.nextLine(); if ("exit".equals(msg)) { System.out.println("离线成功!"); socket.close(); break; } //2.创建一个数据包对象封装数据 byte[] buffer = msg.getBytes(); //封装发送的数据(字节)、发送数据的大小、服务端IP地址(本次使用的是本机)、服务端端口 DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getLoopbackAddress(), 8888); //3.发送数据 socket.send(packet); } } } //服务端 import java.net.DatagramPacket; import java.net.DatagramSocket; public class SercerDemo1 { public static void main(String[] args) throws Exception { //1.创建接收端对象:注册端口 DatagramSocket socket = new DatagramSocket(8888); //2.创建一个数据包对象接收数据 byte[] buffer = new byte[1024 * 64]; DatagramPacket packet = new DatagramPacket(buffer, buffer.length); while (true) { //3.等待接收数据 socket.receive(packet); //4.取出数据 //读取多少取多少 int len = packet.getLength(); String rs = new String(buffer, 0, len); System.out.println("收到了来自:" + packet.getAddress() + ",对方端口是:" + packet.getPort() + "的消息:" + rs); } } }广播、组播TCP协议代码示例(默认不支持多个客户端)-->需要使用多线程去完成处理多个客户端消息(只需服务端进行多线程修改)//客户端 import java.io.OutputStream; import java.io.PrintStream; import java.net.Socket; import java.util.Scanner; public class ClientDemo1 { public static void main(String[] args) { try { //1.创建Socket通信管道请求服务端连接 //服务端IP地址、服务端端口 Socket socket = new Socket("127.0.0.1", 8888); //2.从socket通讯管道中得到一个字节输出流,负责发送 OutputStream os = socket.getOutputStream(); //3.把低级的字节流包装成打印流 PrintStream ps = new PrintStream(os); Scanner sc = new Scanner(System.in); while (true) { System.out.println("请输入你想要发送的消息:"); String msg = sc.nextLine(); //4.发送消息并刷新 ps.println(msg); //注意这里必须至少要一行消息,所有需要使用println ps.flush(); } } catch (Exception e) { throw new RuntimeException(e); } } } //服务端 import java.net.ServerSocket; import java.net.Socket; public class ServerDemo1 { public static void main(String[] args) { //1.注册端口 try { ServerSocket serverSocket = new ServerSocket(7777); //a.定义一个死循环由主线程负责不断地接收客户端的Socket管道连接 while (true) { //2.必须调用accept方法:等待接受客户端的Socket连接请求,建立Socket通信管道 Socket socket = serverSocket.accept(); //用于客户端上线提醒 System.out.println(socket.getRemoteSocketAddress() + "上线了!"); //下面注释代码为不使用线程只能一个客户端使用的情况 // //3.从socket通信管道中得到一个字节输入流 // InputStream is = socket.getInputStream(); // //4.把字节输入流1包装成缓冲字符输入流进行消息接收 // BufferedReader br = new BufferedReader(new InputStreamReader(is)); // //5.按照行读取消息 // String msg; // while ((msg = br.readLine()) != null) { // System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg); // } //3.开始创建独立线程处理Socket new ServerReaderThread(socket).start(); } } catch (Exception e) { throw new RuntimeException(e); } } } //线程类(ServerReaderThread.java) import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.net.Socket; public class ServerReaderThread extends Thread { private Socket socket; public ServerReaderThread(Socket socket) { this.socket = socket; } @Override public void run() { try { //3.从socket通信管道中得到一个字节输入流 InputStream is = socket.getInputStream(); //4.把字节输入流1包装成缓冲字符输入流进行消息接收 BufferedReader br = new BufferedReader(new InputStreamReader(is)); //5.按照行读取消息 String msg; while ((msg = br.readLine()) != null) { System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg); } } catch (Exception e) { //可以用于客户端下线了提醒 System.out.println(socket.getRemoteSocketAddress() + "下线了!"); } } } 使用线程池代码示例//客户端(和之前一样) import java.io.OutputStream; import java.io.PrintStream; import java.net.Socket; import java.util.Scanner; public class ClientDemo1 { public static void main(String[] args) { try { //1.创建Socket通信管道请求服务端连接 //服务端IP地址、服务端端口 Socket socket = new Socket("127.0.0.1", 7777); //2.从socket通讯管道中得到一个字节输出流,负责发送 OutputStream os = socket.getOutputStream(); //3.把低级的字节流包装成打印流 PrintStream ps = new PrintStream(os); Scanner sc = new Scanner(System.in); while (true) { System.out.println("请输入你想要发送的消息:"); String msg = sc.nextLine(); //4.发送消息并刷新 ps.println(msg); //注意这里必须至少要一行消息,所有需要使用println ps.flush(); } } catch (Exception e) { throw new RuntimeException(e); } } } //服务端(使用线程池,完成服务端可以同时处理多个客户端消息) import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.*; public class ServerDemo1 { //使用静态变量记住一个线程池对象 private static ExecutorService pool = new ThreadPoolExecutor(3, 5, 6, TimeUnit.SECONDS, new ArrayBlockingQueue<>(2), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); public static void main(String[] args) { try { //1.注册端口 ServerSocket serverSocket = new ServerSocket(7777); while (true) { //2.每接收到一个客户端的Socket管道 Socket socket = serverSocket.accept(); System.out.println(socket.getRemoteSocketAddress() + "上线了!"); Runnable target = new ServerReaderRunnable(socket); pool.execute(target); } } catch (Exception e) { throw new RuntimeException(e); } } } //线程池类(ServerReaderRunnable.java) import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.net.Socket; public class ServerReaderRunnable implements Runnable { private Socket socket; public ServerReaderRunnable(Socket socket) { this.socket = socket; } @Override public void run() { try { //3.从socket通信管道中得到一个字节输入流 InputStream is = socket.getInputStream(); //4.把字节输入流1包装成缓冲字符输入流进行消息接收 BufferedReader br = new BufferedReader(new InputStreamReader(is)); //5.按照行读取消息 String msg; while ((msg = br.readLine()) != null) { System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg); } } catch (Exception e) { //可以用于客户端下线了提醒 System.out.println(socket.getRemoteSocketAddress() + "下线了!"); } } } 使用线程池优点:实战案例-即时通信//客户端 import java.io.OutputStream; import java.io.PrintStream; import java.net.Socket; import java.util.Scanner; public class ClientDemo1 { public static void main(String[] args) { try { //1.创建Socket通信管道请求服务端连接 //服务端IP地址、服务端端口 Socket socket = new Socket("127.0.0.1", 7777); //创建一个独立的线程专门负责这个客户端的读消息(服务端随时可发消息过来) new ClientReaderThread(socket).start(); //2.从socket通讯管道中得到一个字节输出流,负责发送 OutputStream os = socket.getOutputStream(); //3.把低级的字节流包装成打印流 PrintStream ps = new PrintStream(os); Scanner sc = new Scanner(System.in); while (true) { System.out.println("请输入你想要发送的消息:"); String msg = sc.nextLine(); //4.发送消息并刷新 ps.println(msg); //注意这里必须至少要一行消息,所有需要使用println ps.flush(); } } catch (Exception e) { throw new RuntimeException(e); } } } //客户端线程类(ClientReaderThread.java) import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.net.Socket; public class ClientReaderThread extends Thread { private Socket socket; public ClientReaderThread(Socket socket) { this.socket = socket; } @Override public void run() { try { //3.从socket通信管道中得到一个字节输入流 InputStream is = socket.getInputStream(); //4.把字节输入流1包装成缓冲字符输入流进行消息接收 BufferedReader br = new BufferedReader(new InputStreamReader(is)); //5.按照行读取消息 String msg; while ((msg = br.readLine()) != null) { System.out.println("收到消息:" + msg); } } catch (Exception e) { //可以用于客户端下线了提醒 System.out.println("服务端把你踢出去了"); } } } //服务端 import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.List; public class ServerDemo1 { //定义一个静态的List集合存储当前全部在线的socket管道 public static List<Socket> allOnlineSockets = new ArrayList<>(); public static void main(String[] args) { //1.注册端口 try { ServerSocket serverSocket = new ServerSocket(7777); //a.定义一个死循环由主线程负责不断地接收客户端的Socket管道连接 while (true) { //2.必须调用accept方法:等待接受客户端的Socket连接请求,建立Socket通信管道 //注意,在这里等待客户端的socket管道连接 Socket socket = serverSocket.accept(); //用于客户端上线提醒 System.out.println(socket.getRemoteSocketAddress() + "上线了!"); allOnlineSockets.add(socket); //3.开始创建独立线程处理Socket new ServerReaderThread(socket).start(); } } catch (Exception e) { throw new RuntimeException(e); } } } //服务端线程类(ServerReaderThread.java) import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.Socket; public class ServerReaderThread extends Thread { private Socket socket; public ServerReaderThread(Socket socket) { this.socket = socket; } @Override public void run() { try { //3.从socket通信管道中得到一个字节输入流 InputStream is = socket.getInputStream(); //4.把字节输入流包装成缓冲字符输入流进行消息接收 BufferedReader br = new BufferedReader(new InputStreamReader(is)); //5.按照行读取消息 String msg; while ((msg = br.readLine()) != null) { System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg); //把消息进行端口转发给全部客户端socket管道 sendMsgToAll(msg); } } catch (Exception e) { //可以用于客户端下线了提醒 System.out.println(socket.getRemoteSocketAddress() + "下线了!"); ServerDemo1.allOnlineSockets.remove(socket); } } private void sendMsgToAll(String msg) throws Exception { for (Socket socket : ServerDemo1.allOnlineSockets) { PrintStream ps = new PrintStream(socket.getOutputStream()); ps.println(msg); ps.flush(); } } } 大杂烩单元测试*代码示例:常用注解反射反射的作用1.绕过编译阶段为集合添加数据2.通用框架的底层原理注解自定义注解元注解用在自定义注解上面的注解,用于限制自定义注解注解的解析获取注解里的内容动态代理代理:某些场景下对象会找一个代理对象,来辅助自己完成一些工作案例:通过代理实现方法性能统计优点XML定义:可扩展标记语言,它是一种数据表示格式,可以描述非常复杂的数据结构,常用于传输和存储数据XML解析使用Dom4j解析XMLXpath检索出XML文件
2023年03月03日
454 阅读
0 评论
0 点赞
2023-02-16
Xmind 思维脑图软件破解版
Xmind 破解版安装.exe文件后,登录软件,然后关闭软件。将 winmm.dll 文件移动至安装目录,多次重启直至不显示升级为pro即为破解成功(新建页面)成功截图如图所示 下载地址:夸克网盘链接:https://pan.quark.cn/s/206c375474e8提取码:iwbd
2023年02月16日
848 阅读
0 评论
0 点赞
2022-04-09
MYSQL获取用户连续签到天数
表结构:data date,uid stringSELECT count( 1 ) FROM ( SELECT date_sub( a.data, INTERVAL 1 DAY ) signDate, ( @i := DATE_ADD( @i, INTERVAL - 1 DAY ) ) today FROM ( SELECT data FROM user_dakas WHERE uid = "1" ORDER BY data DESC ) a INNER JOIN ( SELECT @i := max( data ) AS signMax FROM user_dakas WHERE uid = "1" AND ( TO_DAYS( data ) = TO_DAYS( curdate()) OR TO_DAYS( data ) = TO_DAYS( DATE_ADD( curdate(), INTERVAL - 1 DAY ) ) ) ) b WHERE b.signMax IS NOT NULL AND TO_DAYS( DATE_ADD( @i, INTERVAL - 1 DAY )) = TO_DAYS( date_sub( a.data, INTERVAL 1 DAY ) ) ) c
2022年04月09日
509 阅读
0 评论
0 点赞
2022-02-20
分割nohup文件脚本
#!/bin/bash this_path="/www/wwwroot/xxxxx/" #宝塔文件脚本目录地址 current_date=`date -d "-1 day" "+%Y%m%d"` #列出时间 cd $this_path echo $this_path echo $current_date do_split () { [ ! -d logs ] && mkdir -p logs split -b 3m -d -a 4 ./nohup.out ./logs/nohup-${current_date} if [ $? -eq 0 ];then echo "Split is finished!" else echo "Split is Failed!" exit 1 fi } do_del_log() { find ./logs -type f -ctime +7 | xargs rm -rf #清理7天前创建的日志 cat /dev/null > nohup.out #清空当前目录的nohup.out文件 } if do_split ;then do_del_log echo "nohup is split Success" else echo "nohup is split Failure" exit 2 fi将其在宝塔的计划任务中执行shell脚本即可原脚本:#!/bin/bash # Author: Ljohn # Last Update: 2018.02.24 # Description: nohup.out 日志分割 this_path=$(cd `dirname $0`;pwd) #根据脚本所在路径 current_date=`date -d "-1 day" "+%Y%m%d"` #列出时间 cd $this_path echo $this_path echo $current_date do_split () { [ ! -d logs ] && mkdir -p logs split -b 3m -d -a 4 ./nohup.out ./logs/nohup-${current_date} #切分3兆每块至logs文件中,格式为:nohup-xxxxxxxxxx if [ $? -eq 0 ];then echo "Split is finished!" else echo "Split is Failed!" exit 1 fi } do_del_log() { find ./logs -type f -ctime +7 | xargs rm -rf #清理7天前创建的日志 cat /dev/null > nohup.out #清空当前目录的nohup.out文件 } if do_split ;then do_del_log echo "nohup is split Success" else echo "nohup is split Failure" exit 2 fi # crontab -e 添加定时任务:每周第一天的1点执行一次 #0 1 * * */1 /server/scripts/clearNohup.sh &>/dev/null
2022年02月20日
460 阅读
0 评论
0 点赞
1
2
3
...
5