0%

MySQL 日志系统全解析:类型、作用与实战配置

MySQL 的日志系统是数据库运维、故障排查和数据恢复的核心支撑,包含六种关键日志:事务日志(redo log、undo log)、二进制日志(binlog)、错误日志、慢查询日志、一般查询日志、中继日志(relay log)。每种日志各司其职,共同保障数据库的稳定性、可追溯性和一致性。

事务日志:保障事务的 ACID 特性

事务日志是 InnoDB 引擎特有的日志,专门用于保证事务的原子性、一致性和持久性,分为重做日志(redo log)和回滚日志(undo log)。

1. 重做日志(redo log):保证持久性与原子性

核心作用:

当 MySQL 宕机时,通过 redo log 恢复未刷盘的脏页数据,确保事务提交后的数据不丢失(持久性)。

工作原理:

InnoDB 采用 WAL(Write-Ahead Logging,预写式日志) 机制:

  • 数据修改时,先写入内存中的 redo log buffer,再异步 / 同步刷入磁盘的 redo log file
  • 同时修改内存缓冲池(Buffer Pool)中的数据页(脏页),脏页会定期异步刷入磁盘;
  • 若宕机,重启时通过 redo log 回放未刷盘的脏页操作,恢复数据。

redo log 记录的是物理日志(如 “数据页 X 的偏移量 Y 处修改为 Z”),与具体 SQL 无关。

存储与配置:
  • 存储位置:默认在数据目录下,以 ib_logfile0ib_logfile1 命名(循环写入,满后覆盖旧日志)。

  • 关键配置

阅读全文 »

Scala 集合:不可变与可变的完美融合

Scala 集合框架是处理数据集合的核心工具,其设计兼顾了不可变性(线程安全、函数式编程友好)和可变性(性能优化、状态修改),提供了丰富的数据结构(序列、集合、映射等)和操作方法。本文将系统解析 Scala 集合的层级结构、核心类型及常用操作,帮助你高效处理各类数据集合。

集合框架概览

Scala 集合分为两大体系:不可变集合(默认)和可变集合,分别位于不同的包中:

  • 不可变集合scala.collection.immutable,集合创建后无法修改,所有操作返回新集合。

    不可变集合

  • 可变集合scala.collection.mutable,集合可直接修改,操作效率更高。

    可变集合层级关系

核心特质与继承关系

所有集合都扩展自 Iterable 特质,主要分为三大类:

  1. Seq(序列):有序集合(如数组、列表、队列),元素按顺序访问,可通过索引访问。
  2. Set(集合):无序集合,元素唯一,无重复值。
  3. Map(映射):键值对集合,键唯一,值可重复。

序列(Seq)

序列是有序集合,支持索引访问,核心类型包括数组(Array)、变长数组(ArrayBuffer)、列表(List)、队列(Queue)等。

定长数组(Array)

与 Java 数组类似,长度固定,初始化后不可修改,支持泛型。

定义方式
1
2
3
4
5
6
7
// 方式1:指定长度和类型(默认值为0、null等)
val arr1 = new Array[Int](5) // 长度为5的Int数组,默认值0
val arr2 = new Array[String](3) // 长度为3的String数组,默认值null

// 方式2:直接初始化元素(调用apply方法)
val arr3 = Array(1, 2, 3, 4) // Int数组:Array(1, 2, 3, 4)
val arr4 = Array("a", "b", "c") // String数组:Array(a, b, c)
常用操作
阅读全文 »

Scala 隐式转换:编译器背后的 “魔法”

隐式转换(Implicit Conversion)是 Scala 中最强大且独特的特性之一,它允许编译器在特定场景下自动插入转换代码,实现类型适配、功能扩展等操作,而无需开发者显式调用。这种机制既保持了代码的简洁性,又增强了语言的灵活性。本文将系统解析 Scala 隐式函数、隐式参数、隐式类的用法及转换规则。

隐式函数(Implicit Function)

隐式函数是用 implicit 关键字声明的单个参数函数,用于自动将一种类型转换为另一种类型,解决类型不匹配问题。

基本用法:类型自动转换

当编译器发现表达式类型与预期类型不匹配时,会在作用域内搜索合适的隐式函数进行转换。

1
2
3
4
5
6
// 定义隐式函数:将 Double 转换为 Int
implicit def doubleToInt(d: Double): Int = d.toInt

// 预期类型为 Int,实际值为 Double(触发隐式转换)
val num: Int = 3.14 // 等价于 doubleToInt(3.14)
println(num) // 输出:3
核心规则:
  • 隐式函数必须有且仅有一个参数(否则无法自动匹配)。
  • 函数名无特殊要求,但通常以 “源类型 To 目标类型” 命名(如 doubleToInt)。
  • 隐式函数必须在作用域内(可通过 import 引入),否则编译器无法找到。

作用域与可见性

隐式函数的作用域是其生效的关键,编译器只会搜索当前作用域内的隐式函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
object ImplicitConversions {
// 定义在对象中的隐式函数
implicit def stringToInt(s: String): Int = s.toInt
}

object Test {
def main(args: Array[String]): Unit = {
// 引入隐式函数(否则无法使用)
import ImplicitConversions.stringToInt

val age: Int = "25" // 触发 stringToInt 转换
println(age + 5) // 输出:30
}
}

隐式参数(Implicit Parameters)

隐式参数是用 implicit 标记的函数参数,编译器会在调用函数时自动搜索作用域内的隐式值(用 implicit 定义的变量)作为默认值,无需显式传递。

基本用法:自动填充参数

阅读全文 »

Scala 抽象类:未完成的类与强制实现的契约

抽象类是面向对象编程中用于定义未完成逻辑的类,它包含抽象成员(抽象方法或抽象字段),需要子类实现才能被实例化。Scala 的抽象类机制与 Java 类似,但在语法和灵活性上有细微差异,尤其在抽象成员的定义和实现上更为简洁。本文将详细解析 Scala 抽象类的特性、定义方式及使用场景。

抽象类的基本定义

Scala 中抽象类通过 abstract 关键字声明,可包含抽象成员(无实现的方法或未初始化的字段)和具体成员(有实现的方法或已初始化的字段)。

语法格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
abstract class 类名 {
// 抽象字段(未初始化)
字段类型 字段名: 类型

// 抽象方法(无方法体)
def 方法名(参数列表): 返回值类型

// 具体字段(已初始化)
val/var 具体字段名: 类型 = 初始值

// 具体方法(有方法体)
def 具体方法名(参数列表): 返回值类型 = {
// 方法体
}
}

示例:定义抽象类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 抽象类:Animal(动物)
abstract class Animal {
// 抽象字段:未初始化的名字和年龄
var name: String
val age: Int // val 抽象字段也需子类初始化

// 抽象方法:无实现的呼吸方法
def breath(): Unit

// 具体字段:所有动物共有的属性
val category: String = "生物"

// 具体方法:所有动物共有的行为
def eat(): Unit = {
println(s"$name 在吃东西")
}
}

核心特性

  1. 不能实例化:抽象类本身不完整,无法直接通过 new 实例化(与 Java 相同)。

阅读全文 »

Scala 类型检查:对象类型的判断与转换

在面向对象编程中,类型检查和转换是处理多态场景的重要手段。Scala 提供了一套简洁而强大的 API 用于判断对象类型、转换类型及获取类信息,其功能与 Java 类似但语法更灵活。本文将详细解析 Scala 中的类型检查方法及其应用场景。

获取类信息(classOf 与 getClass)

在 Scala 中,获取类的元信息(Class 对象)主要通过 classOf 关键字和 getClass 方法,两者用途不同但互补。

classOf [T]:获取指定类型的 Class 对象

classOf[T] 用于直接获取类型 T 的 Class 对象,类似于 Java 中的 T.class,无需实例化对象。

1
2
3
4
5
6
7
8
// 获取 String 类型的 Class 对象
val stringClass: Class[String] = classOf[String]
println(stringClass) // 输出:class java.lang.String

// 获取自定义类的 Class 对象
class Person
val personClass: Class[Person] = classOf[Person]
println(personClass) // 输出:class Person

适用场景

  • 编译期已知类型,需获取其元信息(如反射、类型判断)。
  • 作为方法参数传递类型标识(如集合的 isInstanceOf 检查)。

obj.getClass:获取对象实例的运行时类

getClass 是任何对象都能调用的方法(继承自 Any),返回对象实际运行时类型的 Class 对象(可能与声明类型不同,体现多态)。

1
2
3
4
5
6
7
8
class Animal
class Dog extends Animal

// 声明类型为 Animal,实际类型为 Dog
val animal: Animal = new Dog()

println(animal.getClass) // 输出:class Dog(运行时类型)
println(classOf[Animal]) // 输出:class Animal(声明类型)

关键点

  • getClass 返回对象的实际类型(多态场景下至关重要)。
  • classOf[T] 的区别:前者依赖实例,后者依赖类型声明。

类型判断(isInstanceOf [T])

isInstanceOf[T] 用于判断对象是否为类型 T 或其子类的实例,类似于 Java 中的 obj instanceof T,返回布尔值。

基本用法

阅读全文 »