精华内容
下载资源
问答
  • 2021-08-15 21:38:02

    大家好!我是只谈技术不剪发的 Tony 老师。

    SQL 标准使用 CREATE TABLE 语句创建数据表;MySQL 则实现了三种创建表的方法,支持自定义表结构或者通过复制已有的表结构来创建新表,本文给大家分别介绍一下这些方法的使用和注意事项。

    如果你觉得文章有用,欢迎评论📝、点赞👍、推荐🎁

    CREATE TABLE

    CREATE TABLE 语句的基本语法如下:

    CREATE TABLE [IF NOT EXISTS] table_name
    (
      column1 data_type column_constraint,
      column2 data_type,
      ...,
      table_constraint
    );
    

    使用该语句时,我们需要手动定义表的结构。以上包含的内容如下:

    • IF NOT EXISTS 表示当该表不存在时创建表,当表已经存在时不执行该语句。
    • table_name 指定了表的名称。
    • 括号内是字段的定义;columnN 是字段的名称,data_type 是它的数据类型;column_constraint 是可选的字段约束;多个字段使用逗号进行分隔。
    • table_constraint 是可选的表级约束。

    其中,常见的约束包括主键、外键、唯一、非空、检查约束以及默认值。

    举例来说,以下语句用于创建一个新表 department:

    CREATE TABLE department
        ( dept_id    INTEGER NOT NULL PRIMARY KEY
        , dept_name  VARCHAR(50) NOT NULL
        ) ;
    

    部门表 department 包含两个字段,部门编号(dept_id)是一个整数类型(INTEGER),不可以为空(NOT NULL),同时它还是这个表的主键(PRIMARY KEY)。部门名称(dept_name)是一个可变长度的字符串,最长 50 个字符,不允许为空。

    如果我们想要创建一个自定义名称的主键约束,可以使用表级约束:

    CREATE TABLE department
        ( dept_id    INTEGER NOT NULL
        , dept_name  VARCHAR(50) NOT NULL
        , CONSTRAINT pk_department PRIMARY KEY (dept_id)
        ) ;
    

    表级约束在所有字段之后定义,其中 pk_dept 是自定义的主键名称。

    对于数字类型的主键字段,我们可以通过自增长列(auto increment)自动生成一个唯一的数字。例如:

    CREATE TABLE department
        ( dept_id    INTEGER AUTO_INCREMENT PRIMARY KEY
        , dept_name  VARCHAR(50) NOT NULL
        ) ;
    

    此时,我们在插入数据时不再需要为 dept_id 字段提供数据,MySQL 默认会产生一个从 1 开始,每次递增 1 的数字序列。

    然后我们再创建两个表:

    CREATE TABLE job
        ( job_id         INTEGER NOT NULL PRIMARY KEY
        , job_title      VARCHAR(50) NOT NULL
        ) ;
        
    CREATE TABLE employee
        ( emp_id    INTEGER NOT NULL PRIMARY KEY
        , emp_name  VARCHAR(50) NOT NULL
        , sex       VARCHAR(10) NOT NULL
        , dept_id   INTEGER NOT NULL
        , manager   INTEGER
        , hire_date DATE NOT NULL
        , job_id    INTEGER NOT NULL
        , salary    NUMERIC(8,2) NOT NULL
        , bonus     NUMERIC(8,2)
        , email     VARCHAR(100) NOT NULL
        , CONSTRAINT ck_emp_sex CHECK (sex IN ('男', '女'))
        , CONSTRAINT ck_emp_salary CHECK (salary > 0)
        , CONSTRAINT uk_emp_email UNIQUE (email)
        , CONSTRAINT fk_emp_dept FOREIGN KEY (dept_id) REFERENCES department(dept_id)
        , CONSTRAINT fk_emp_job FOREIGN KEY (job_id) REFERENCES job(job_id)
        , CONSTRAINT fk_emp_manager FOREIGN KEY (manager) REFERENCES employee(emp_id)
        ) ;
    

    job 表用于存储职位信息,和部门表相似,比较简单。

    employee 表用于存储员工信息,包含的字段和约束如下:

    • 员工编号(emp_id)是一个整数类型(INTEGER),不可以为空(NOT NULL),同时它还是这个表的主键(PRIMARY KEY)。
    • 员工姓名(emp_name)是一个可变长度的字符串,最长 50 个字符,不允许为空。
    • 性别(sex)是一个可变长度的字符串,最长 10 个字符,不允许为空;另外,我们通过表级约束 ck_emp_sex 限制了性别的取值只能为“男”或者“女”。
    • 部门编号(dept_id)代表了员工所在的部门,因此通过外键约束 fk_emp_dept 引用了部门表的主键字段。
    • 经理编号(manager)代表了员工的直接上级,可能为空。外键约束 fk_emp_manager 表示经理也属于员工。
    • 入职日期(hire_date)是一个 DATE 类型的字段,不能为空。
    • 职位编号(job_id)代表了员工的职位,因此通过外键 fk_emp_job 引用了职位表的主键字段。
    • 月薪(salary)是一个支持两位小数的数字,不能为空。检查约束 ck_emp_salary 要求月薪必须大于零。
    • 奖金(bonus)是一个可选的数字字段。
    • 电子邮箱(email)是一个可变长度的字符串,最长100 个字符,不允许为空。检查约束 uk_emp_email 要求每个员工的电子邮箱都不相同。

    CREATE TABLE … LIKE

    除了手动定义表的结构之外,MySQL 还提供了复制已有表结构的方法:

    CREATE TABLE [IF NOT EXISTS] table_name
        { LIKE old_tbl_name | (LIKE old_tbl_name) }
    

    MySQL 的 LIKE 语法只复制表结构,包括字段的属性和索引,但是不复制数据。例如:

    CREATE TABLE emp_copy
      LIKE employee;
    

    以上语句基于 employee 表的结构复制生成一个新的表 emp_copy。

    mysql> show create table emp_copy \G
    *************************** 1. row ***************************
           Table: emp_copy
    Create Table: CREATE TABLE `emp_copy` (
      `emp_id` int NOT NULL,
      `emp_name` varchar(50) NOT NULL,
      `sex` varchar(10) NOT NULL,
      `dept_id` int NOT NULL,
      `manager` int DEFAULT NULL,
      `hire_date` date NOT NULL,
      `job_id` int NOT NULL,
      `salary` decimal(8,2) NOT NULL,
      `bonus` decimal(8,2) DEFAULT NULL,
      `email` varchar(100) NOT NULL,
      PRIMARY KEY (`emp_id`),
      UNIQUE KEY `uk_emp_email` (`email`),
      KEY `fk_emp_dept` (`dept_id`),
      KEY `fk_emp_job` (`job_id`),
      KEY `fk_emp_manager` (`manager`),
      CONSTRAINT `emp_copy_chk_1` CHECK ((`salary` > 0)),
      CONSTRAINT `emp_copy_chk_2` CHECK ((`sex` in (_utf8mb4'男',_utf8mb4'女')))
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
    1 row in set (0.01 sec)
    

    对于 CREATE TABLE … LIKE 命令,目标表会保留原始表中的主键、唯一约束、非空约束、表达式默认值、检查约束(自动生成约束名),同时还会保留原始表中的计算列定义。

    CREATE TABLE … LIKE 命令不会保留外键约束(但是会保留外键索引),以及任何 DATA DIRECTORY 或者 INDEX DIRECTORY 表属性选项。

    如果原始表是一个 TEMPORARY 表,CREATE TABLE … LIKE 不会保留 TEMPORARY 关键字。如果想要创建一个临时表,可以使用 CREATE TEMPORARY TABLE … LIKE。

    使用 mysql 表空间、InnoDB 系统表空间(innodb_system)或者通用表空间创建的表包含一个 TABLESPACE 属性,表示该表所在的表空间。目前,无论 innodb_file_per_table 设置为什么参数,CREATE TABLE … LIKE 都会保留 TABLESPACE 属性。为了避免复制新表时使用原始表的 TABLESPACE 属性,可以使用下面介绍的第三种方法。例如:

    CREATE TABLE new_tbl SELECT * FROM orig_tbl LIMIT 0;
    

    以上语句会基于 orig_tbl 创建一个新的空表 new_tbl,具体参考下一节内容。

    CREATE TABLE … LIKE 使用原始表的所有 ENGINE_ATTRIBUTE 和 SECONDARY_ENGINE_ATTRIBUTE 值创建目标表。

    另外,LIKE 只能基于表进行复制,而不能复制视图。

    CREATE TABLE … SELECT

    在 MySQL 中复制表结构的另一种方法就是利用查询语句的结果定义字段和复制的数据:

    CREATE TABLE table_name
      [AS] SELECT ...;
    

    其中的 SELECT 语句定义了新表的结构和数据。以下示例基于查询的结果创建了一个新表:emp_devp,表中包含了研发部的所有员工。

    CREATE TABLE emp_devp
        AS
    SELECT e.*
      FROM employee e
      JOIN department d
        ON (d.dept_id = e.dept_id AND d.dept_name = '研发部');
    

    对于这种语法,MySQL 实际上是在已有目标表中增加新的字段。例如:

    CREATE TABLE t1(col1 INTEGER, col2 INTEGER);
    INSERT INTO t1(col1, col2) VALUES(1, 1), (2, 4);
    
    CREATE TABLE t2(id INTEGER AUTO_INCREMENT PRIMARY KEY)
           ENGINE=InnoDB
        AS SELECT col1, col2 FROM t1;
    

    我们首先为 t2 指定了一个自增 id,然后将 t1 的查询结果添加到该字段的后面。其中,ENGINE 选项属于 CREATE TABLE 语句,因此需要位于 SELECT 语句之前。

    查询 t2 可以看到以上语句不仅复制了表结构,同时还复制了 t1 中的数据:

    TABLE t2;
    
    +----+------+------+
    | id | col1 | col2 |
    +----+------+------+
    |  1 |    1 |    1 |
    |  2 |    2 |    4 |
    +----+------+------+
    2 rows in set (0.00 sec)
    

    如果只想复制结构,不需要复制数据,可以在查询语句中增加 LIMIT 0 或者 WHERE 1=0 条件。

    如果在 SELECT 语句前面增加 IGNORE 或者 REPLACE 关键字,可以处理复制数据时导致唯一键冲突的数据行。对于 IGNORE,源数据中和目标表重复的数据行就会被丢弃;对于 REPLACE,使用新数据行替换目标表中的已有数据行。如果没有指定任何选项,唯一键冲突将会返回错误。

    CREATE TABLE … SELECT 命令不会自动创建任何索引,这样可以使得该语句尽量灵活。如果想要创建索引,可以在 SELECT 语句之前指定。例如:

    CREATE TABLE t3(id INTEGER PRIMARY KEY)
    AS SELECT col1 as id, col2 FROM t1;
    

    CREATE TABLE … SELECT 命令不会保留计算列的定义,也不会保留默认值定义。同时某些数据类型可能产生转换。例如,AUTO_INCREMENT 属性不会被保留,VARCHAR 类型被转换为 CHAR 类型。保留的属性包括 NULL(NOT NULL)以及 CHARACTER SET、COLLATION、COMMENT 和 DEFAULT 子句。

    使用 CREATE TABLE … SELECT 命令创建表时,需要为查询语句中的函数和表达式指定一个别名,否则该命令可能失败或者创建意料之外的字段名:

    CREATE TABLE artists_and_works
    SELECT artist.name, COUNT(work.artist_id) AS number_of_works
    FROM artist LEFT JOIN work ON artist.id = work.artist_id
    GROUP BY artist.id;
    

    对于 CREATE TABLE … SELECT 命令,如果我们指定了 IF NOT EXISTS 并且目标表已经存在,不会将数据复制到目标表,同时该语句不会写入日志文件。

    CREATE TABLE … SELECT 命令不支持 FOR UPDATE 选项。

    CREATE TABLE … SELECT 命令只会应用字段的 ENGINE_ATTRIBUTE 和 SECONDARY_ENGINE_ATTRIBUTE 属性。表和索引的 ENGINE_ATTRIBUTE 和 SECONDARY_ENGINE_ATTRIBUTE 属性不会被应用,除非为目标表明确指定这些选项。

    总结

    本文通过一些案例介绍了 MySQL 中三种创建表的方法和注意事项。

    如果你想要了解更多 MySQL 入门知识,可以参考这篇文章

    更多相关内容
  • 非标准名称数据表,例如:cow_archives_4,类似命名方法常见于齐博cms,08cms等文档模型数据表命名,假设已在配置文件中配置数据表前缀: 复制代码 代码如下:<?php  return array(   //’配置项’=>’配置值’   ...
  • docker创建镜像的三种方法

    千次阅读 2020-08-17 08:50:05
    创建docker镜像的三种方法,分别是基于已有的容器创建、基于本地模板创建、以及dockerfile创建。 1.基于以有容器创建镜像。 基于已有的容器创建主要是使用docker commit命令。实质就是把一个容器里面运行的程序以及...

    在工作中我们交付给你客户的往往都是一些定定制的容器,但是在这之前我们要先学会怎么去创建镜像来交付
    一、docer创建镜像的创建方法
    创建docker镜像的三种方法,分别是基于已有的容器创建、基于本地模板创建、以及dockerfile创建。
    1.基于以有容器创建镜像。
    基于已有的容器创建主要是使用docker commit命令。实质就是把一个容器里面运行的程序以及该程序的运行环境打包起来生成新的镜像。
    命令:docker commit 选项 容器ID/名称 仓库名称:标签
    常用的选项:
    -m:说明信息
    -a:作者
    -p:生成过程中停止容器的运行(一般不会使用)
    在这里插入图片描述

    2.基于本地模板镜像创建:
    通过导入操作系模板文件可以生成镜像,模板可以从OPENVZ开源项目下载,下载地址为:https://wiki.openvz.org/Download/template/precreated

    Cat 镜像包 | docker import - 生成的镜像名:标签
    在这里插入图片描述在这里插入图片描述
    3.用dockerfile生成镜像:
    Dockerfile结构的四个部分:基本镜像信息,维护者信息,镜像操作指令和容器启动执行指令:
    3.1:建立工作目录:
    [root@123456 ~]# mkdir myapache
    [root@123456 ~]# cd myapache/

    3.2创建并编写dockerfile文件:
    在这里插入图片描述
    3.3编写执行脚本文件:
    [root@123456 myapache]# vim run.sh

    #!/bin/bash
    rm -rf /run/httpd/*
    exec /usr/sbin/apachectl -D FOREGROUND
    在这里插入图片描述
    3.4创建测试页面:
    [root@123456 myapache]# echo “then is httpd”>index.html
    [root@123456 myapache]# ls
    Dockerfile index.html run.sh
    在这里插入图片描述

    3.5使用dockerfile生存镜像文件:
    命令docker build 选项 路径
    常用选项:
    -t:指定镜像的标签选项。
    [root@123456 myapache]# docker build -t centos:httpd .
    在这里插入图片描述
    3.6使用新的镜像运行容器:
    将容器中的暴露端口映射到宿主机上端口号为8888
    [root@123456 myapache]# docker run -it -d -p 8888:80 centos:httpd
    c3b0432591612bf0697404e4044eeb45d42e072ea27388e8b498697a2ebb7436

    在这里插入图片描述

    3.7用真实主机去访问宿主机加映射的端口号:
    在这里插入图片描述
    4.将镜像上层到仓库:
    为dockerfile创建的镜像添加别名(如果要上传到公共仓库需要在前面标签你的docker hub账号)
    [root@123456 myapache]# docker tag centos:httpd zj199711/centos:httpd
    在这里插入图片描述
    上传成功:
    在这里插入图片描述

    5.创建私有仓库:
    可以使用registry来搭建本地私有仓库:

    5.1需要在构建私有仓库的服务器上下载registry镜像
    [root@123456 ~]# docker pull registry
    Using default tag: latest
    之后需要在/etc/docker/目录下创建一个json文件。否则在往自定义的私有仓库中上传镜像是会包错:
    [root@123456 ~]# vim /etc/docker/daemon.json

    {
    “registry-mirrors”: [“https://5fpngg16.mirror.aliyuncs.com”]
    }
    {
    “insecure-registres”: [“172.16.16.200:5000”]

    }
    在这里插入图片描述
    5.2
    使用registry镜像创建一个容器,默认情况下仓库放于容器内的/tmp/registry目录下,使用-v选项可以将本地目录挂载到容器内的/tmp/registry下使用这样就不怕容器被删除后镜像也会随之丢失:(默认的监听端口为registry 5000端口号)
    将创建的容器5000的端口号映射到本机:
    [root@123456 ~]# docker run -d -p 5000:5000 -v /data/registry:/tmp/registry registry
    5c70a2c6ae9722696bf9004e5dcc637f2bef9ba621be15948b08d461fa515bfb
    在这里插入图片描述
    使用docker tag 命令将要上传的镜像标记为宿主机的IP/+镜像名
    [root@123456 ~]# docker tag centos:httpd 172.16.16.200:5000/centos:httpd
    在这里插入图片描述
    用docker push上传标记的镜像:
    在这里插入图片描述

    展开全文
  • 线程池的使用(7种创建方法

    千次阅读 多人点赞 2022-04-13 12:07:25
    线程池的7种创建方法
    线程池的创建⽅法总共有 7 种,但总体来说可分为 2 类:
            1. 通过 ThreadPoolExecutor 创建的线程池;
            2. 通过 Executors 创建的线程池。
    线程池的创建⽅式总共包含以下 7 种(其中 6 种是通过 Executors 创建的, 1 种是通过
    ThreadPoolExecutor 创建的):
            1. Executors.newFixedThreadPool:创建⼀个固定⼤⼩的线程池,可控制并发的线程数,超出的线程会在队列中等待;
            2. Executors.newCachedThreadPool:创建⼀个可缓存的线程池,若线程数超过处理所需,缓存⼀段时间后会回收,若线程数不够,则新建线程;
            3. Executors.newSingleThreadExecutor:创建单个线程数的线程池,它可以保证先进先出的执⾏顺序;
            4. Executors.newScheduledThreadPool:创建⼀个可以执⾏延迟任务的线程池;
            5. Executors.newSingleThreadScheduledExecutor:创建⼀个单线程的可以执⾏延迟任务的线程池;

            6. Executors.newWorkStealingPool:创建⼀个抢占式执⾏的线程池(任务执⾏顺序不确定)【JDK1.8 添加】。
            7. ThreadPoolExecutor:最原始的创建线程池的⽅式,它包含了 7 个参数可供设置,后⾯会详细讲。

     1. 固定数量的线程池

    public class ThreadPoolDemo3 {
        public static void main(String[] args) {
            ExecutorService threadPool = Executors.newFixedThreadPool(2);
            //添加任务方式 1
            threadPool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            });
    
            //添加任务方式2
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            });
        }
    }
    输出:
    pool-1-thread-1
    pool-1-thread-2

    a.  线程池返回结果

    public class ThreadPoolDemo4 {
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            ExecutorService threadPool =  Executors.newFixedThreadPool(2);
            //执行任务
            Future<Integer> result = threadPool.submit(new Callable<Integer>() {
                @Override
                public Integer call() throws Exception {
                    int num = new Random().nextInt(10);
                    System.out.println("随机数" + num);
                    return num;
                }
            });
    
            //打印线程池返回方式
            System.out.println("返回结果:" + result.get());
        }
    }
    输出
    随机数8
    返回结果:8

    使用submit可以执行有返回值的任务或者是无返回值的任务;而execute只能执行不带返回值的任务。 

    b. ⾃定义线程池名称或优先级

    public class ThreadPoolDemo5 {
        public static void main(String[] args) throws ExecutionException, InterruptedException {
             // 创建线程工厂
            ThreadFactory threadFactory = new ThreadFactory() {
                @Override
                public Thread newThread(Runnable r) {
                    //!!!!!!!一定要注意:要把任务Runnable设置给新创建的线程
                    Thread thread = new Thread(r);
                    //设置线程的命名规则
                    thread.setName("我的线程" + r.hashCode());
                    //设置线程的优先级
                    thread.setPriority(Thread.MAX_PRIORITY);
                    return thread;
                }
            };
            ExecutorService threadPool = Executors.newFixedThreadPool(2,threadFactory);
            //执行任务1
            Future<Integer> result = threadPool.submit(new Callable<Integer>() {
                @Override
                public Integer call() throws Exception {
                    int num = new Random().nextInt(10);
                    System.out.println(Thread.currentThread().getPriority() + ", 随机数:" + num);
                    return num;
                }
            });
            //打印线程池返回结果
            System.out.println("返回结果:" + result.get());
        }
    }
    

     提供的功能:

            1. 设置(线程池中)线程的命名规则。

            2. 设置线程的优先级。

            3. 设置线程分组。

            4. 设置线程类型(用户线程、守护线程)。

    2. 带缓存的线程池

    public class ThreadPoolDemo6 {
        public static void main(String[] args) {
            //创建线程池
            ExecutorService service = Executors.newCachedThreadPool();
            for (int i = 0; i < 10; i++) {
                int finalI = i;
                service.submit(() -> {
                    System.out.println("i : " + finalI + "|线程名称:" + Thread.currentThread().getName());
                });
            }
        }
    }
    输出
    i : 1|线程名称:pool-1-thread-2
    i : 4|线程名称:pool-1-thread-5
    i : 3|线程名称:pool-1-thread-4
    i : 5|线程名称:pool-1-thread-6
    i : 0|线程名称:pool-1-thread-1
    i : 2|线程名称:pool-1-thread-3
    i : 6|线程名称:pool-1-thread-7
    i : 7|线程名称:pool-1-thread-8
    i : 8|线程名称:pool-1-thread-9
    i : 9|线程名称:pool-1-thread-1

     优点:线程池会根据任务数量创建线程池,并且在一定时间内可以重复使用这些线程,产生相应的线程池。

    缺点:适用于短时间有大量任务的场景,它的缺点是可能会占用很多的资源。

    3. 执⾏定时任务

    a. 延迟执⾏(⼀次)

    public class ThreadPoolDemo7 {
        public static void main(String[] args) {
            //创建线程池
            ScheduledExecutorService service = Executors.newScheduledThreadPool(5);
            System.out.println("添加任务的时间:" + LocalDateTime.now());
            //执行定时任务(延迟3s执行)只执行一次
            service.schedule(new Runnable() {
                @Override
                public void run() {
                    System.out.println("执行子任务:" + LocalDateTime.now());
                }
            },3, TimeUnit.SECONDS);
        }
    }
    输出
    添加任务的时间:2022-04-13T14:19:39.983
    执行子任务:2022-04-13T14:19:42.987

      

    b. 固定频率执⾏

    public class ThreadPoolDemo8 {
        public static void main(String[] args) {
            //创建线程池
            ScheduledExecutorService service = Executors.newScheduledThreadPool(5);
            System.out.println("添加任务时间:" + LocalDateTime.now());
            //2s之后开始执行定时任务,定时任务每隔4s执行一次
            service.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    System.out.println("执行任务:" + LocalDateTime.now());
                }
            },2,4, TimeUnit.SECONDS);
        }
    }
    输出
    添加任务时间:2022-04-13T14:24:38.810
    执行任务:2022-04-13T14:24:40.814
    执行任务:2022-04-13T14:24:44.814
    执行任务:2022-04-13T14:24:48.813
    执行任务:2022-04-13T14:24:52.815
    执行任务:2022-04-13T14:24:56.813
    执行任务:2022-04-13T14:25:00.813
    执行任务:2022-04-13T14:25:04.814
    执行任务:2022-04-13T14:25:08.813
    ... ...
    ... ...
    执行任务:2022-04-13T14:26:44.814
    执行任务:2022-04-13T14:26:48.813

     注意事项:

    public class ThreadPoolDemo9 {
        public static void main(String[] args) {
            //创建线程池
            ScheduledExecutorService service = Executors.newScheduledThreadPool(5);
            System.out.println("添加任务时间:" + LocalDateTime.now());
            service.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    System.out.println("执行任务: " + LocalDateTime.now());
                    try {
                        Thread.sleep(5 * 1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },2,4, TimeUnit.SECONDS);
        }
    }
    输出
    添加任务时间:2022-04-13T14:33:34.551
    执行任务: 2022-04-13T14:33:36.556
    执行任务: 2022-04-13T14:33:41.557
    执行任务: 2022-04-13T14:33:46.559
    执行任务: 2022-04-13T14:33:51.561
    执行任务: 2022-04-13T14:33:56.562
    执行任务: 2022-04-13T14:34:01.564
    执行任务: 2022-04-13T14:34:06.566
    执行任务: 2022-04-13T14:34:11.566
    执行任务: 2022-04-13T14:34:16.567
    执行任务: 2022-04-13T14:34:21.570
    执行任务: 2022-04-13T14:34:26.570
    ... ....

    c. scheduleAtFixedRate VS scheduleWithFixedDelay

    scheduleAtFixedRate 是以上⼀次任务的开始时间,作为下次定时任务的参考时间的(参考时间+延迟任务=任务执⾏)。
    scheduleWithFixedDelay 是以上⼀次任务的结束时间,作为下次定时任务的参考时间的。
    public class ThreadPoolDemo10 {
        public static void main(String[] args) {
            //创建线程池
            ScheduledExecutorService service = Executors.newScheduledThreadPool(5);
            System.out.println("添加任务时间:" + LocalDateTime.now());
            //2s之后开始执行定时任务,定时任务每隔4s执行一次
            service.scheduleWithFixedDelay(new Runnable() {
                @Override
                public void run() {
                    System.out.println("执行任务:" + LocalDateTime.now());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, 2, 4, TimeUnit.SECONDS);
        }
    }
    输出
    添加任务时间:2022-04-13T14:46:02.871
    执行任务:2022-04-13T14:46:04.876
    执行任务:2022-04-13T14:46:09.878
    执行任务:2022-04-13T14:46:14.880
    执行任务:2022-04-13T14:46:19.883
    执行任务:2022-04-13T14:46:24.885
    执行任务:2022-04-13T14:46:29.888
    执行任务:2022-04-13T14:46:34.888
    执行任务:2022-04-13T14:46:39.891
    执行任务:2022-04-13T14:46:44.893
    执行任务:2022-04-13T14:46:49.895
    执行任务:2022-04-13T14:46:54.897
    执行任务:2022-04-13T14:46:59.900
    执行任务:2022-04-13T14:47:04.901
    ... ...
    

    4. 定时任务单线程

    public class ThreadPoolDemo11 {
        public static void main(String[] args) {
            ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
            System.out.println("添加任务的时间:" + LocalDateTime.now());
            service.schedule(new Runnable() {
                @Override
                public void run() {
                    System.out.println("执行时间:" + LocalDateTime.now());
                }
            },2, TimeUnit.SECONDS );
        }
    }
    输出
    添加任务的时间:2022-04-13T15:06:38.100
    执行时间:2022-04-13T15:06:40.106

    5. 单线程线程池

    public class ThreadPoolDemo12 {
        public static void main(String[] args) {
            ExecutorService service = Executors.newSingleThreadScheduledExecutor();
            for (int i = 0; i < 10; i++) {
                service.submit(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("线程名:" + Thread.currentThread().getName());
                    }
                });
            }
        }
    }
    输出
    线程名:pool-1-thread-1
    线程名:pool-1-thread-1
    线程名:pool-1-thread-1
    线程名:pool-1-thread-1
    线程名:pool-1-thread-1
    线程名:pool-1-thread-1
    线程名:pool-1-thread-1
    线程名:pool-1-thread-1
    线程名:pool-1-thread-1
    线程名:pool-1-thread-1
    

    (MS) 为什么不直接用线程?

    单线程的线程池又什么意义?

            1. 复用线程。

            2. 单线程的线程池提供了任务队列和拒绝策略(当任务队列满了之后(Integer.MAX_VALUE),新来的任务就会拒绝策略)

    6. 根据当前CPU⽣成线程池

    public class ThreadPoolDemo13 {
        public static void main(String[] args) {
            ExecutorService service = Executors.newWorkStealingPool();
            for (int i = 0; i < 10; i++) {
                service.submit(() -> {
                    System.out.println("线程名" + Thread.currentThread().getName());
                });
                
                while(!service.isTerminated()) {
                }
            }
        }
    }
    输出
    线程名ForkJoinPool-1-worker-1

    7. ThreadPoolExecutor

    线程池的使用(7种创建方法)_Youcan.的博客-CSDN博客https://blog.csdn.net/m0_48273471/article/details/124171220

    展开全文
  • Docker镜像创建方法

    2021-01-11 05:44:27
    命令格式:docker commit [选项] 容器ID/名称 仓库名称:[标签] 常用命令选项: -m:说明信息 -a:作者信息 -p:生成过程中停止容器的运行 例: 首先启动一个镜像,在容器里修改,然后将修改的镜像生成新的镜像,...
  • js常用的几种创建对象的方式有: {} new Object() 使用字面量 工厂模式 构造函数模式(constructor) 原型模式(prototype) 构造函数+原型模式 还有一些不常用的方式,如动态原型,寄生构造函数,稳妥构造函数。 ...

    js常用的几种创建对象的方式有:

    1、{}
    2、new Object()
    3、使用字面量
    4、工厂模式
    5、构造函数模式(constructor)
    6、原型模式(prototype)
    7、构造函数+原型模式

    还有一些不常用的方式,如动态原型,寄生构造函数,稳妥构造函数。

    一、通过{}创建对象

      <script>
            'use strict'; //使用strict模式
    
            /**
            使用{}创建对象,等同于 new Object();
            **/
            var o = {};
    
            o.name = 'jack';
            o.age = 20;
    
            o.sayName = function(){
                alert(this.name);
            }
    
            alert(o.name+'-'+o.age);
    
            o.sayName();
    
        </script>
    

    如果对象不用重复创建,这种方式是比较方便的。

    二、通过new Object()创建对象

    <script>
            'use strict';
            // 使用 new Object() 创建对象
            var o = new Object();
            o.name = "zhangsna";
            o.sayName = function(){
                alert(this.name);
            }
    
            o.sayName();
    
            alert('o instanceof Object>>>>>>>>>>>'+(o instanceof Object));//true
            alert("typeof o >>>>> "+typeof o);//object
        </script>
    

    三、使用字面量创建对象

    对象字面变量是对象定义的一种简写形式,举个例子:
    var person = {name: 'zhang', age:20}, 这就是字面量形式,完全等价于var person = {}; person.name='zhang'; person.age=20;

    小结:前面三种创建对象的方式存在2个问题:1.代码冗余; 2.对象中的方法不能共享,每个对象中的方法都是独立的。

    四、使用工厂模式创建对象

    这种方式是使用一个函数来创建对象,减少重复代码,解决了前面三种方式的代码冗余的问题,但是方法不能共享的问题还是存在。

    <script>
            'use strict';
    
            // 使用工厂模式创建对象
            // 定义一个工厂方法
            function createObject(name){
                var o = new Object();
                o.name = name;
                o.sayName = function(){
                    alert(this.name);
                };
                return o;
            }
    
            var o1 = createObject('zhang');
            var o2 = createObject('li');
    
            //缺点:调用的还是不同的方法
            //优点:解决了前面的代码重复的问题
            alert(o1.sayName===o2.sayName);//false
    
        </script>
    

    五、通过构造函数创建对象

    所谓构造函数,也是普通的函数,不过约定俗成,构造函数的名称首字母大写,普通函数的首字母小写。通过new 构造函数来创建对象。

     <script>
            'use strict';
    
            /**
             *  构造函数模式创建对象
             **/
            function Person(name){
                this.name = name;
                this.sayName = function(){
                    alert(this.name);
                };
            }
    
            var p1 = new Person('zhang');
            var p2 = new Person('li');
    
            p1.sayName();
            p2.sayName();
    
            alert(p1.constructor === p2.constructor);//true
            alert(p1.constructor === Person);//true
    
            alert(typeof(p1));//object
    
            alert(p1 instanceof Object); //true
            alert(p2 instanceof Object); //trueb
    
            alert(p1.sayName===p2.sayName);//false
    
        </script>
    

    在这里插入图片描述

    通过内存模型,可以发现,sayName函数是独立存在于每个对象的,所以p1.sayName===p2.sayName结果为false,还是没有解决方法不能共享的问题。

    六、通过原型模式创建对象

    每个方法中都有一个原型(prototype),每个原型都有一个构造器(constructor),构造器又指向这个方法。

    举个例子:

    function Animal(){}
    alert(Animal.prototype.constructor==Animal);//true
    

    原型创建对象:

      <script>
            'use strict';
    
            /*
             *  原型模式创建对象
             */
            function Animal() { }
    
            Animal.prototype.name = 'animal';
            Animal.prototype.sayName = function () { alert(this.name); };
    
            var a1 = new Animal();
            var a2 = new Animal();
    
            a1.sayName();
    
            alert(a1.sayName === a2.sayName);//true
            alert(Animal.prototype.constructor);//function Animal(){}
            alert(Animal.prototype.constructor==Animal);//true
        </script>
    

    通过原型创建对象,把属性和方法绑定到prototype上,通过这种方式创建对象,方法是共享的,每个对象调用的是同一个方法。

    在这里插入图片描述
    如果往新建的对象中加入属性,那么这个属性是放在对象中,如果存在与原型同名的属性,也不会改变原型的值。但是访问这个属性,拿到的是对象的值。

    访问的顺序:对象本身>构造函数的prototype

    如果对象中没有该属性,则去访问prototype,如果prototype中没有,继续访问父类,直到Object,如果都没有找到,返回undefined

     <script>
            'use strict';
            /*
             *  原型模式创建对象
             */
            function Animal() { }
            Animal.prototype.name = 'animal';
            Animal.prototype.sayName = function () { alert(this.name); };
    
            var a1 = new Animal();
            var a2 = new Animal();
            a1.sayName();
            alert(a1.sayName === a2.sayName);//true
            alert(Animal.prototype.constructor);//function Animal(){}
            //修改a2.name,a1的name不会变
            a2.name = 'dog';
            a2.sayName();//dog
            a1.sayName();//animal
     </script>
    

    在这里插入图片描述
    这种方式创建的对象会存在问题,假如原型中包含有引用类型的属性,那么如果某个对象修改了该属性的值,所有的该原型创建的对象访问的值都会改变。

     <script>
            'use strict';
    
            //原型模式2
            //存在的问题:如果原型中含有引用类型
            function Animal (){}
            Animal.prototype = {
                name: 'animal',
                friends: ['dog','cat'],
                sayName: function(){
                    alert(this.name);
                }
            };
            var a1 = new Animal();
            var a2 = new Animal();
            a2.friends.push('snake');
            alert(a2.friends);//[dog,cat,snake]
            alert(a1.friends);//[dog,cat,snake]
    
      </script>
    

    在这里插入图片描述

    七、通过原型+构造函数的方式创建对象

    这种方式结合了上面两种方式,解决了代码冗余,方法不能共享,引用类型改变值的问题。

     <script>
            'use strict';
    
            function Animal(name){
                this.name = name;
                this.friends = ['dog','cat'];
            }
            Animal.prototype.sayName = function(){
                alert(this.name);
            };
            var a1 = new Animal('d');
            var a2 = new Animal('c');
            a1.friends.push('snake');
            alert(a1.friends);//[dog,cat,snake]
            alert(a2.friends);//[dog,cat]
    
      </script>
    

    在这里插入图片描述

    https://www.jianshu.com/p/1fb0447db852

    展开全文
  • 主要介绍了PHP中获取文件创建日期、修改日期、访问时间的方法,有时候我们需要获取页面生成的时间,防止重复生成。需要的朋友可以参考下
  • 一维数组创建的几种方法

    千次阅读 2018-04-07 22:14:10
    数组可以说是对于每语言学习中的最基础的数据结构之一,几乎是在所有项目中都会涉及到数组的使用,接下来就详细介绍一下数组的声明、创建和初始化以及实例代码解析,以Java语言描述 声明 数据类型 数组名称[]...
  • 主要介绍了Java线程操作的常见方法,结合实例形式总结分析了java线程的创建、线程名称的获取、设置以及线程启动的判断等相关操作实现技巧,需要的朋友可以参考下
  • 线程池创建4种方式与参数详解

    千次阅读 2021-03-08 16:15:43
    Executors 是 Executor 的工具类,提供了4种创建不同线程池的方式,来满足业务的需求。底层是调ThreadPoolExecutor类构造方法。 二、Executors中线程池创建4种方式 newFixedThreadPool:创建的是定长的线程池,...
  • 对象是对类的实例化。对象具有状态和行为,变量用来表明对象的状态,...对象的显式创建方式有 4 。 1. 使用 new 关键字创建对象 这是常用创建对象的方法,语法格式如下: 类名 对象名=new 类名(); 2. 调...
  • Java创建线程的常用的两种方法

    千次阅读 2014-08-09 11:27:13
    1创建线程的方法-----继承Thread类 java.lang.Thread是java中用来表示线程的类,其中定义的许多方法为完成线程的处理工作提供了比较完整的功能。如果将一个类定义为Thread的子类,那么这个类也就可以表示线程。 ...
  • Cookie的创建和读取和常用方法

    千次阅读 2021-05-29 18:12:14
    b)如何创建 Cookie Servlet 程序中的代码: public class CookieServlet extends BaseServlet { /** * 创建Cookie * @param req * @param resp * @throws ServletException * @throws IOException */ ...
  • * 创建线程的第二方式:实现Runnable接口 */ public class Thread02 { public static void main(String[] args) { // 创建Runnable实例对象 Demo01 d = new Demo01("阳光"); // 创建线程对象,...
  • 本文实例分析了js中匿名函数的创建与调用方法。分享给大家供大家参考。具体实现方法如下: 匿名函数就是没有名字的函数了...匿名函数主要有两种常用的场景,一是回调函数,二是直接执行函数。 回调函数,像ajax的异步操
  • 文章目录一、Spring容器创建Bean对象的四种方式1.通过反射调用构造方法创建bean对象2.通过实例工厂方法创建bean对象3.通过静态实例工厂方法创建bean对象4.通过FactoryBean接口来创建bean对象二、bean对象的作用范围...
  • js创建对象的几方式

    千次阅读 2021-02-25 13:04:32
    js常用的几种创建对象的方式有: {} new Object() 使用字面量 工厂模式 构造函数模式(constructor) 原型模式(prototype) 构造函数+原型模式 还有一些不常用的方式,如动态原型,寄生构造函数,稳妥构造函数。 ...
  • 创建线程 - Python教程 - C语言网

    千次阅读 2021-05-23 06:54:58
    线程有个变化状态:1)创建线程当创建一个新的进程时,也创建一个新的线程,进程中的线程可以在同一进程中创建新的线程。2)终止线程可以正常终止自己,也可能某个线程执行错误,由其它线程强行终止。终止线程操作...
  • 创建表的几方式(语法总结)

    千次阅读 2020-11-17 17:56:34
    小伙伴们好啊,今天和大家说说用M和DAX创建表的几方式。 我们需要创建的表格如下: 使用DAX创建表 首先来看一常用的方式: 方法一:使用DATATABLE创建,实现的代码如下: Employees_1 = DATATABLE ( "Name",...
  • 总结:常见创建对象的几方式

    千次阅读 2019-04-28 17:33:58
    1.通过Object构造函数或对象字面量创建单个对象 Var obj=new Object(); //在外部生成 Var person={name:’aa’,age:12}; 缺点:使用同一个接口创建很多对象,会产生大量的重复代码 2.工厂模式:在一个函数内创建好...
  • 这个模块提供了一方便的使用操作系统函数的方法。 os常用方法 在磁盘中创建一个测试文件夹 os.rename(oldname, newname) 1、修改文件夹的名称 >>> os.listdir('E:\\python_cmd\\test_1') ['test_1_1'] >>> os....
  • 各位小伙伴们大家好,这次小编要讲的是Thread类的一个常用方法,获取线程名称。在之前的文章中,小编介绍了Java之多线程原理的内存图解。获取当前线程的名称有两种方法1.使用Thread类中的方法getName(),String ...
  • 创建数组的两方式

    2019-07-02 16:28:02
    1.1 let 变量名称 = new Array(size) //创建一个指定大小的数组 1.2 let 变量名称 = new Array() //创建一个空的数组 1.3 let 变量名称 = new Array(data1,data2,…) //创建一个带数据的数组 2.通过字面量创建数组 ...
  • 创建bean的几种常见方法

    千次阅读 2016-09-19 18:25:23
    通过调用静态工厂方法创建 Bean ...要声明通过静态方法创建的 Bean, 需要在 Bean 的 class 属性里指定拥有该工厂的方法的类, 同时在 factory-method 属性里指定工厂方法名称. 最后, 使用 元素为该方法传递方法参数.
  • Spring:创建Bean的几方式

    万次阅读 多人点赞 2016-06-04 17:42:21
    Spring创建工厂的三方式
  • MySQL常用的三备份方法

    千次阅读 2021-01-28 02:57:49
    mysql按照备份恢复方式分为逻辑备份和物理...这2备份各有优劣,一般来说,物理备份恢复速度比较快,占用空间比较大,逻辑备份速度比较慢,占用空间比较小下面介绍以下3种常用的备案方法一、mysqldump工具备份mysq...
  • 二、Class类的常用方法 1、getName() 一个Class对象描述了一个特定类的属性,Class类中最常用方法getName以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。 2、new...
  • 文章目录创建 SparkContext 对象RDD 创建方式1. 创建并行化集合RDD(parallelize、makeRDD)parallelizemakeRDD2. 从外部存储系统创建RDD(textfile)3. 从RDD衍生新的RDD(原地计算)4. 小文件读取(wholeTextFiles...
  • 多线程之创建线程的两方式

    万次阅读 多人点赞 2018-05-29 00:33:56
    彩蛋: ...言归正传,今晚准备详细记录一下线程创建的两方式以及这两方式的优缺点及适应的情况等等。 多进程:。。。 多线程:在一个应用程序中,有多个顺序流同时执行。(线程:顺序执行的代...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 976,417
精华内容 390,566
关键字:

创建名称常用的四种方法

友情链接: LorenzPoincare.rar