要查看MySQL数据库占用的空间大小,可以按照以下步骤操作:

  1. 连接到MySQL服务器
    使用命令行工具(如MySQL Shell、命令提示符或终端)或者MySQL客户端软件(如phpMyAdmin、Navicat等),通过适当的认证信息(如用户名、密码、主机名等)连接到目标MySQL服务器。
  2. 选择要查看的数据库
    在已经连接到MySQL服务器的环境中,执行以下SQL命令,选择您感兴趣的数据库:

    USE 数据库名称;

    数据库名称 替换为您想要查询其空间占用的实际数据库名称。

  3. 查询数据库占用空间
    使用以下SQL语句从INFORMATION_SCHEMA系统数据库中获取所需信息:

    SELECT 
        TABLE_NAME, 
        TABLE_ROWS, 
        ROUND(DATA_LENGTH / 1024 / 1024, 2) AS Data_MB, 
        ROUND(INDEX_LENGTH / 1024 / 1024, 2) AS Index_MB, 
        ROUND((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024, 2) AS Total_MB
    FROM 
        INFORMATION_SCHEMA.TABLES 
    WHERE 
        TABLE_SCHEMA = '数据库名称';

    这个查询将返回每个表的名称、行数以及它们分别占用的数据空间(Data_MB)、索引空间(Index_MB)和总空间(Total_MB),单位均为兆字节(MB)。如果您想查看所有表占用空间的总计,可以进一步使用SUM函数汇总:

    SELECT 
        SUM(DATA_LENGTH) AS Total_Data_Length,
        SUM(INDEX_LENGTH) AS Total_Index_Length,
        SUM(DATA_LENGTH + INDEX_LENGTH) AS Total_Size
    FROM 
        INFORMATION_SCHEMA.TABLES 
    WHERE 
        TABLE_SCHEMA = '数据库名称';

    结果将显示数据库中所有表的总数据长度、总索引长度以及总的磁盘空间占用量。

请注意,这些查询提供的空间大小是基于磁盘上的数据文件和索引文件,不包括可能存在的临时文件、日志文件或其他与数据库相关的元数据。如果您还需要考虑这些额外因素,可能需要结合系统文件管理工具(如dudf命令)或MySQL服务器的配置参数来获取更全面的磁盘使用情况。同时,若要查看数据库在内存中的占用情况(如InnoDB缓冲池使用量),则需要查询不同的系统变量或状态信息。

在 Linux 中创建 swap 分区通常分为以下几个步骤:

1. 确定 swap 大小
根据系统需求和可用磁盘空间,决定要创建的 swap 分区大小。一般建议 swap 大小至少为物理内存的 2 倍,但具体大小可以根据实际工作负载和服务器资源进行调整。例如,如果物理内存为 4 GB,则可以考虑创建一个 8 GB 的 swap 分区。

2. 创建 swap 文件
有两种常见方法创建 swap 文件:

a) 使用 dd 命令创建一个空白文件,并将其格式化为 swap 文件。例如,创建一个 2 GB 的 swap 文件:

sudo dd if=/dev/zero of=/swapfile bs=1G count=2

b) 使用 fallocate 命令快速分配空间创建 swap 文件(如果系统支持):

sudo fallocate -l 8G /swapfile

上述命令会在根目录下创建一个名为 swapfile 的文件,大小分别为 2 GB 和 8 GB,根据第 1 步确定的实际大小进行调整。

3. 格式化为 swap 文件系统
使用 mkswap 命令将创建的文件格式化为 swap 文件系统:

sudo mkswap /swapfile

4. 激活 swap 分区
使用 swapon 命令激活刚刚创建的 swap 文件:

sudo swapon /swapfile

这时,新创建的 swap 分区应该已经生效。可以通过 free -h 命令来验证 swap 分区是否已成功添加并被系统识别:

free -h

5. 使 swap 分区设置持久化
若要确保重启后 swap 分区仍能自动挂载,需要将其添加到 /etc/fstab 文件中:

echo '/swapfile none swap defaults 0 0' | sudo tee -a /etc/fstab

这行命令将指定的 swap 文件路径、文件系统类型、挂载选项等信息追加到 /etc/fstab 文件中,确保系统启动时自动挂载 swap。

6. 可选:调整 swappiness 参数
可以通过修改 /etc/sysctl.conf 文件中的 vm.swappiness 参数来调整系统使用 swap 的倾向。默认值通常为 60,如果希望减少 swap 使用,可以降低该值(比如设为 30)。编辑文件并添加或修改如下行:

sudo vi /etc/sysctl.conf

在打开的文件中加入或修改以下行:

vm.swappiness=30

保存文件后,执行 sudo sysctl -p 使更改立即生效,或者重启系统让更改在下次启动时生效。

完成以上步骤后,您已经在 Linux 系统上成功创建了一个持久化的 swap 分区。如果在后续使用过程中需要调整 swap 大小或删除 swap 分区,请参照相应的操作指南进行操作。

窗口函数 RANK(), DENSE_RANK(), or ROW_NUMBER(): MySQL 8.0及更高版本引入了窗口函数,它们提供了更直观和精确的方式来获取记录的名次。这里分别介绍三种常用的窗口函数:

SELECT name, score, RANK() OVER (ORDER BY score DESC) AS ranks FROM students WHERE name = '小明';

RANK():给每个分区内的行分配一个唯一的名次,遇到相同的值时,所有相同的行得到相同的名次,下一个不同的值的名次跳过与相同值相同数量的名次。例如:

DENSE_RANK():类似于RANK(),但不会跳过任何名次,即使遇到相同的值。这意味着连续的名次之间不会有间隔。

ROW_NUMBER():为每个分区内的行提供一个唯一的连续整数作为名次,即使值相同,也会赋予不同的名次。

使用这些窗口函数,您可以直接在查询结果中获取特定记录的名次,同时考虑到了可能存在的分数相同的情况。如果您使用的是MySQL 8.0及以上版本,强烈建议使用这种方式。

总结起来,要获取MySQL中特定记录在排序后的名次,可以依据数据库版本和需求选择合适的方法:

对于MySQL 8.0及以上版本,优先使用窗口函数(如RANK(), DENSE_RANK(), 或 ROW_NUMBER())。
对于旧版本MySQL(< 8.0),可以使用变量累加法或子查询结合COUNT()函数,但需注意这些方法可能存在局限性(如并发问题、无法处理分数相同情况等)。

1.配置文件找不到beans元素:可能是xsd与spring版本不一致,导致无法效验;

解决方案:将applicationContext.xml中xsd文件定义的版本改为spring jar包中定义的xsd的版本,如果版本定义的太高在本地会无法找到,只能从网络上下载。

  第二,在dtd中缺少 xmlns="http://www.springframework.org/schema/beans"也会出现这个问题。
解决方法:在spring配置文件中加入xmlns="http://www.springframework.org/schema/beans即可解决。
可参考:https://www.cnblogs.com/longshiyVip/p/4574070.html#undefined

2.java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/springmvc-servlet.xm】

对于Maven项目,如果不特意指定参数名为contextConfigLoction的元素,那么spring的ContextLoderListener监听器就会在/WEB-INF/下去寻找并加载该目录下的名为applicationContext.xml这个文件

不可变对象想必大部分朋友都不陌生,大家在平时写代码的过程中100%会使用到不可变对象,比如最常见的String对象、包装器对象等,那么到底为何Java语言要这么设计,真正意图和考虑点是什么?可能一些朋友没有细想过这些问题,今天我们就来聊聊跟不可变对象有关的话题。

  以下是本文目录大纲:

  一.什么是不可变对象

  二.深入理解不可变性

  三.如何创建不可变对象

  四.不可变对象真的"完全不可改变"吗?

一.什么是不可变对象
  下面是《Effective Java》这本书对于不可变对象的定义:

1
不可变对象(Immutable Object):对象一旦被创建后,对象所有的状态及属性在其生命周期内不会发生任何变化。
  从不可变对象的定义来看,其实比较简单,就是一个对象在创建后,不能对该对象进行任何更改。比如下面这段代码:

public class ImmutableObject {

private int value;
 
public ImmutableObject(int value) {
    this.value = value;
}
 
public int getValue() {
    return this.value;
}

}
  由于ImmutableObject不提供任何setter方法,并且成员变量value是基本数据类型,getter方法返回的是value的拷贝,所以一旦ImmutableObject实例被创建后,该实例的状态无法再进行更改,因此该类具备不可变性。

  再比如我们平时用的最多的String:

public class Test {

public static void main(String[] args) {
    String str = "I love java";
    String str1 = str;

    System.out.println("after replace str:" + str.replace("java", "Java"));
    System.out.println("after replace str1:" + str1);
}

}
  输出结果:

  

  从输出结果可以看出,在对str进行了字符串替换替换之后,str1指向的字符串对象仍然没有发生变化。

二.深入理解不可变性
  我们是否考虑过一个问题:假如Java中的String、包装器类设计成可变的ok么?如果String对象可变了,会带来哪些问题?

  我们这一节主要来聊聊不可变对象存在的意义。

1)让并发编程变得更简单
  说到并发编程,可能很多朋友都会觉得最苦恼的事情就是如何处理共享资源的互斥访问,可能稍不留神,就会导致代码上线后出现莫名其妙的问题,并且大部分并发问题都不是太容易进行定位和复现。所以即使是非常有经验的程序员,在进行并发编程时,也会非常的小心,内心如履薄冰。

  大多数情况下,对于资源互斥访问的场景,都是采用加锁的方式来实现对资源的串行访问,来保证并发安全,如synchronize关键字,Lock锁等。但是这种方案最大的一个难点在于:在进行加锁和解锁时需要非常地慎重。如果加锁或者解锁时机稍有一点偏差,就可能会引发重大问题,然而这个问题Java编译器无法发现,在进行单元测试、集成测试时可能也发现不了,甚至程序上线后也能正常运行,但是可能突然在某一天,它就莫名其妙地出现了。

  既然采用串行方式来访问共享资源这么容易出现问题,那么有没有其他办法来解决呢?

  事实上,引起线程安全问题的根本原因在于:多个线程需要同时访问同一个共享资源。

  假如没有共享资源,那么多线程安全问题就自然解决了,Java中提供的ThreadLocal机制就是采取的这种思想。

  然而大多数时候,线程间是需要使用共享资源互通信息的,如果共享资源在创建之后就完全不再变更,如同一个常量,而多个线程间并发读取该共享资源是不会存在线上安全问题的,因为所有线程无论何时读取该共享资源,总是能获取到一致的、完整的资源状态。

  不可变对象就是这样一种在创建之后就不再变更的对象,这种特性使得它们天生支持线程安全,让并发编程变得更简单。

  我们来看一个例子,这个例子来源于:http://ifeve.com/immutable-objects/

public class SynchronizedRGB {

private int red;  // 颜色对应的红色值
private int green; // 颜色对应的绿色值
private int blue;  // 颜色对应的蓝色值
private String name; // 颜色名称

private void check(int red, int green, int blue) {
    if (red < 0 || red > 255 || green < 0 || green > 255
            || blue < 0 || blue > 255) {
        throw new IllegalArgumentException();
    }
}

public SynchronizedRGB(int red, int green, int blue, String name) {
    check(red, green, blue);
    this.red = red;
    this.green = green;
    this.blue = blue;
    this.name = name;
}

public void set(int red, int green, int blue, String name) {
    check(red, green, blue);
    synchronized (this) {
        this.red = red;
        this.green = green;
        this.blue = blue;
        this.name = name;
    }
}

public synchronized int getRGB() {
    return ((red << 16) | (green << 8) | blue);
}

public synchronized String getName() {
    return name;
}

}
  例如一个有个线程1执行了以下代码:

SynchronizedRGB color = new SynchronizedRGB(0, 0, 0, "Pitch Black");
int myColorInt = color.getRGB(); // Statement1
String myColorName = color.getName(); // Statement2
  然后有另外一个线程2在Statement 1之后、Statement 2之前调用了color.set方法:

color.set(0, 255, 0, "Green");
  那么在线程1中变量myColorInt的值和myColorName的值就会不匹配。为了避免出现这样的结果,必须要像下面这样把这两条语句绑定到一块执行:

synchronized (color) {

int myColorInt = color.getRGB();
String myColorName = color.getName();

}
  假如SynchronizedRGB是不可变类,那么就不会出现这个问题,比如将SynchronizedRGB改成下面这种实现方式:

public class ImmutableRGB {

private int red;
private int green;
private int blue;
private String name;

private void check(int red, int green, int blue) {
    if (red < 0 || red > 255 || green < 0 || green > 255
            || blue < 0 || blue > 255) {
        throw new IllegalArgumentException();
    }
}

public ImmutableRGB(int red, int green, int blue, String name) {
    check(red, green, blue);
    this.red = red;
    this.green = green;
    this.blue = blue;
    this.name = name;
}

public ImmutableRGB set(int red, int green, int blue, String name) {
    return new ImmutableRGB(red, green, blue, name);
}

public int getRGB() {
    return ((red << 16) | (green << 8) | blue);
}

public String getName() {
    return name;
}

}
  由于set方法并没有改变原来的对象,而是新创建了一个对象,所以无论线程1或者线程2怎么调用set方法,都不会出现并发访问导致的数据不一致的问题。

2)消除副作用
  很多时候一些很严重的bug是由于一个很小的副作用引起的,并且由于副作用通常不容易被察觉,所以很难在编写代码以及代码review过程中发现,并且即使发现了也可能会花费很大的精力才能定位出来。

  举个简单的例子:

class Person {

private int age;   // 年龄
private String identityCardID;  // 身份证号码

public int getAge() {
    return age;
}

public void setAge(int age) {
    this.age = age;
}

public String getIdentityCardID() {
    return identityCardID;
}

public void setIdentityCardID(String identityCardID) {
    this.identityCardID = identityCardID;
}

}

public class Test {

public static void main(String[] args) {
    Person jack = new Person();
    jack.setAge(101);
    jack.setIdentityCardID("42118220090315234X");

    System.out.println(validAge(jack));

    
    // 后续使用可能没有察觉到jack的age被修改了
    // 为后续埋下了不容易察觉的问题

}

public static boolean validAge(Person person) {
    if (person.getAge() >= 100) {
        person.setAge(100);  // 此处产生了副作用
        return false;
    }
    return true;
}

}
  validAge函数本身只是对age大小进行判断,但是在这个函数里面有一个副作用,就是对参数person指向的对象进行了修改,导致在外部的jack指向的对象也发生了变化。

  如果Person对象是不可变的,在validAge函数中是无法对参数person进行修改的,从而避免了validAge出现副作用,减少了出错的概率。

3)减少容器使用过程出错的概率
  我们在使用HashSet时,如果HashSet中元素对象的状态可变,就会出现元素丢失的情况,比如下面这个例子:
class Person {

private int age;   // 年龄
private String identityCardID;  // 身份证号码

public int getAge() {
    return age;
}

public void setAge(int age) {
    this.age = age;
}

public String getIdentityCardID() {
    return identityCardID;
}

public void setIdentityCardID(String identityCardID) {
    this.identityCardID = identityCardID;
}

@Override
public boolean equals(Object obj) {
    if (obj == null) {
        return false;
    }

    if (!(obj instanceof  Person)) {
        return false;
    }
    Person personObj = (Person) obj;
    return this.age == personObj.getAge() && this.identityCardID.equals(personObj.getIdentityCardID());
}

@Override
public int hashCode() {
    return age * 37 + identityCardID.hashCode();
}

}

public class Test {

public static void main(String[] args) {
    Person jack = new Person();
    jack.setAge(10);
    jack.setIdentityCardID("42118220090315234X");

    Set<Person> personSet = new HashSet<Person>();
    personSet.add(jack);

    jack.setAge(11);

    System.out.println(personSet.contains(jack));

}

}
 输出结果:

  

  所以在Java中,对于String、包装器这些类,我们经常会用他们来作为HashMap的key,试想一下如果这些类是可变的,将会发生什么?后果不可预知,这将会大大增加Java代码编写的难度。

三.如何创建不可变对象
  通常来说,创建不可变类原则有以下几条:

  1)所有成员变量必须是private

  2)最好同时用final修饰(非必须)

  3)不提供能够修改原有对象状态的方法

最常见的方式是不提供setter方法

如果提供修改方法,需要新创建一个对象,并在新创建的对象上进行修改

  4)通过构造器初始化所有成员变量,引用类型的成员变量必须进行深拷贝(deep copy)

  5)getter方法不能对外泄露this引用以及成员变量的引用

  6)最好不允许类被继承(非必须)

  JDK中提供了一系列方法方便我们创建不可变集合,如:

Collections.unmodifiableList(List<? extends T> list)
  另外,在Google的Guava包中也提供了一系列方法来创建不可变集合,如:

ImmutableList.copyOf(list)
  这2种方式虽然都能创建不可变list,但是两者是有区别的,JDK自带提供的方式实际上创建出来的不是真正意义上的不可变集合,看unmodifiableList方法的实现就知道了:

  可以看出,实际上UnmodifiableList是将入参list的引用复制了一份,同时将所有的修改方法抛出UnsupportedOperationException。因此如果在外部修改了入参list,实际上会影响到UnmodifiableList,而Guava包提供的ImmutableList是真正意义上的不可变集合,它实际上是对入参list进行了深拷贝。看下面这段测试代码的结果便一目了然:

public class Test {

public static void main(String[] args) {
    List<Integer> list = new ArrayList<Integer>();
    list.add(1);
    System.out.println(list);

    List unmodifiableList = Collections.unmodifiableList(list);
    ImmutableList immutableList = ImmutableList.copyOf(list);

    list.add(2);
    System.out.println(unmodifiableList);
    System.out.println(immutableList);

}

}
  输出结果:

四.不可变对象真的"完全不可改变"吗?
  不可变对象虽然具备不可变性,但是不是"完全不可变"的,这里打上引号是因为通过反射的手段是可以改变不可变对象的状态的。

  大家看到这里可能有疑惑了,为什么既然能改变,为何还叫不可变对象?这里面大家不要误会不可变的本意,从不可变对象的意义分析能看出来对象的不可变性只是用来辅助帮助大家更简单地去编写代码,减少程序编写过程中出错的概率,这是不可变对象的初衷。如果真要靠通过反射来改变一个对象的状态,此时编写代码的人也应该会意识到此类在设计的时候就不希望其状态被更改,从而引起编写代码的人的注意。下面是通过反射方式改变不可变对象的例子:

public class Test {

public static void main(String[] args) throws Exception {
    String s = "Hello World";
    System.out.println("s = " + s);

    Field valueFieldOfString = String.class.getDeclaredField("value");
    valueFieldOfString.setAccessible(true);

    char[] value = (char[]) valueFieldOfString.get(s);
    value[5] = '_';
    System.out.println("s = " + s);
}

}