Spring 高级装配

上一篇文章已经讲解了 spring 依赖注入装配的方法。但是为了处理一些特殊的问题,或者为了更好地实现某些功能,spring 还提供了更多的装配设置。 一、条件化声明 Bean 让我们回到上一篇第一节的例子,假设这次我们需要在开发时使用 SQLite,而在生产环境使用 Oracle 要怎么办呢? 或许可以这样,我们在生产环境注意将 DBUtil Bean 改成 Oracle,把原来的部分注释掉,就像是这样。 @Bean public DBUtil databaseUtil() { // return new SQLiteUtil(); // for dev return new OracleUtil(); // for prod } 但这样做很明显是不合适的。如果许多组件都需要进行调整的话,修改上就会十分复杂,且很容易出错。 我们可以使用注释 @Profile 实现不同环境条件下选择不同的装配方式。这需要给带有 @Bean 或 @Configuration 注释的方法或类添加注释 @Profile("某某环境")。于是数据库的选择就可以改为如下形式: @Bean @Profile("dev") public DBUtil sqliteUtil() { return new SQLiteUtil(); } @Bean @Profile("prod") public DBUtil oracleUtil() { return new OracleUtil(); } 想要启用某个 Bean 需要设置环境。具体来说,这通过两个环境变量来实现,spring.profiles.default 和 spring.profiles.active。这两个值可以在许多地方定义。一种方式是在 properties 或 yaml 文件中定义,如...

一月 10, 2023 · 3 分钟 · 502 字 · Wokron

Spring 依赖注入

一、依赖注入 考虑这样一个例子,CustomerDAO 类使用了 DBUtil 类中的方法连接到 MySQL 数据库 public class CustomerDAO { private DBUtil databaseUtil = new DBUtil(); public Customer findCustomerByName(String name) { databaseUtil.doSomething() } } 假设现在想要改为使用 Oracle 数据库,需要怎么做?可以使用 OracleDBUtil 继承 DBUtil,并重写其相关方法。但是由于 CustomerDAO 中将 DBUtil 实例添加到其初始化过程中。因此想要修改的话还是需要对 CustomerDAO 本身进行修改。这违反了开-闭原则。 public class CustomerDAO { private DBUtil databaseUtil = new OracleDBUtil(); public Customer findCustomerByName(String name) { databaseUtil.doSomething() } } 为了使对 dbUtil 的修改不影响 CustomerDAO 本身,我们可以将实例的创建移到 CustomerDAO 之外。 public class CustomerDAO { private DBUtil databaseUtil; public CustomerDAO(DBUtil databaseUtil) { this....

一月 9, 2023 · 3 分钟 · 481 字 · Wokron

Django 创建表结构

一、对象关系映射(ORM) 面向对象与关系型数据库中的数据存储方式并不匹配,因此为了在编程中实现对数据库的操作,需要 ORM 技术将数据库中数据映射到对象之中。通过对对象的操作,做到对数据库的操作,从而实现增删改查等功能。 面向对象编程中,“关系”体现在类与其属性之间以及同一类的不同属性之间;而在关系型数据库中,“关系”体现在同一表中的不同列字段中。 二、django 的 ORM 实现 django 通过 models.Model 类来对应数据库中的表结构,如 class User(models.Model): 即表示了 User 类,也对应了数据库中的 user 表。django 会根据类的声明自动在数据库中建表。 django 用类中的属性来表示表的列字段。如 class User(models.Model): id = models.IntegerField(primary_key=True) name = models.CharField(max_length=50) password = models.CharField(max_length=50) 定义了 user 表的主键、名字、密码信息。 表间关系通过类与其属性表示,如 class User(models.Model): id = models.IntegerField(primary_key=True) name = models.CharField(max_length=50) password = models.CharField(max_length=50) courses = models.ManyToManyField(to="Course") courses 属性表示用户具有的课程,反映了用户与课程之间的关系。 三、类属性与数据库字段的对应 如上一节所述,django 建立了类属性与数据库字段之间的对应关系。常见的如 models.CharField models.TextField models.IntegerField models.FloatField 就对应了数据库中的 char(n),text,int,float 类型。不一一详述。 四、主键与外键 在表中要定义主键,作为该表一条记录的唯一标识。相应的,在 django 中定义主键需要在对应属性上添加 primary_key=True 参数。例如...

一月 9, 2023 · 2 分钟 · 234 字 · Wokron

用 Pytorch 搭建神经网络

一、前言 本文作为自己学习 pytorch 的记录。以搭建一个神经网络为例,介绍 pytorch 的基本使用。 本文不会讲 conda、python、pycharm 等的配置和使用,也不会讲各神经层的原理及使用。只是按照自己之前学习的理解,总结神经网络训练的基本流程。 本文所使用的例子是自己写的第一个神经网路,如下: import os.path import torch.utils.data from torch.utils.data import DataLoader from torch import nn from torch.utils.tensorboard import SummaryWriter from torchvision import transforms, datasets device = torch.device("cpu") if torch.cuda.is_available(): print("cuda available, use cuda to train module") device = torch.device("cuda") train_set = datasets.CIFAR10("./CIFAR10", transform=transforms.ToTensor(), download=True) test_set = datasets.CIFAR10("./CIFAR10", transform=transforms.ToTensor(), train=False, download=True) train_set_size = len(train_set) test_set_size = len(test_set) print(f"train set size: {train_set_size}") print(f"test set size: {test_set_size}") train_dataloader = DataLoader(train_set, 64, shuffle=True, drop_last=True) test_dataloader = DataLoader(test_set, 64) class MyModule(nn....

一月 2, 2023 · 5 分钟 · 884 字 · Wokron

MySQL 的中文插入问题

一、问题描述 在执行一个sql脚本的时候出现了这样的问题: ERROR 1366 (HY000): Incorrect string value: '\xA3\x8E\xE6\x9C\x89\xE5...' for column 'name_zh' at row 1 问题很明显是由于中文引起的。查看报错的语句: INSERT INTO `admin_menu` VALUES ('1', '/admin', 'AdminIndex', '首页', 'el-icon-s-home', 'AdminIndex', '0'); 是 “首页” 无法被识别。考虑是字符集的问题。 二、问题处理 情况一:数据库字符集与脚本所用字符集不一致 第一种可能是数据库所用的字符集和脚本字符集不一致,比如说建表时使用的字符集为 latin1,而脚本使用的却是 utf-8,这样就会导致错误。 输入命令,查看建库语句 SHOW CREATE DATABASE wj; +--------------+----------------------------------------------------------------------------------------------------------------------------------------+ | Database | Create Database | +--------------+----------------------------------------------------------------------------------------------------------------------------------------+ | white_jotter | CREATE DATABASE `wj` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci */ /*!80016 DEFAULT ENCRYPTION='N' */ | +--------------+----------------------------------------------------------------------------------------------------------------------------------------+ 显示所用字符集为 utf8mb4,说明数据库字符集与脚本所用字符集一致。...

十二月 31, 2022 · 2 分钟 · 252 字 · Wokron

系统编程之线程管理

一、Linux 多线程简述 进程和线程的关系老生常谈。线程是最小的调度单位,进程是最小的资源分配单位。同一进程中的多个线程是在共享的内存空间中并发的多道执行路径,它们共享一个进程的资源。 对于Linux来说,Linux线程属于用户级线程,即线程的调度是在用户空间执行的。也就是说,Linux线程的实现是在内核之外的,多线程的概念对于内核来说并不是真实存在的,而只是通过线程库中的程序模拟的并发效果。 Linux线程遵循POSIX线程接口,称为pthread。pthread在其他平台也有对应的实现,如在windows。 二、线程操作 (1)库的使用 在开始多线程编程之前,需要说明一下 pthread.h 库。在编译使用pthread.h库的代码时,一般需要加-lpthread。pthread在glibc2.34之前是在glibc里面的,之后分出来变成一个单独的库,因此有的情况下,不加-lpthread也能编译成功。 (2)基本操作 创建线程 int pthread_create(pthread_t _Nullable * _Nonnull __restrict, const pthread_attr_t * _Nullable __restrict, void * _Nullable (* _Nonnull)(void * _Nullable), void * _Nullable __restrict); 该函数中第一个参数为指向一个线程标识变量的指针。第二个参数用来手动设置线程的各项属性,一般可以用NULL选择默认属性。第三个参数为一个函数指针,表示新建线程时需要执行的函数。注意该函数的参数类型和返回值类型,使用时需要进行强制类型转换。第四个参数为传递给函数的参数,也就是线程执行的函数的参数。不传递参数时可设置为NULL。 如下举一个创建线程的例子。 pthread_t tid; if (pthread_create(&tid, NULL, do_something, NULL)) { // error handler } 线程退出 void pthread_exit(void *ral_ptr); 当某一线程执行该函数时,会导致该线程结束。结束时会将ral_ptr指针传递给pthread_join 函数的 rval_ptr 线程取消 int pthread_cancel(pthread_t tid); 某一线程调用该函数,可以终止同一进程内的其他线程。 tid 即要终止的线程。 线程挂起 int pthread_join(pthread_t thread, void **rval_ptr); 某一线程调用该函数会阻塞该线程,直到参数 thread 所指示的线程退出。第二个参数为一个指向 pthread_exit 所设置的 ral_ptr 指针的指针。...

十二月 22, 2022 · 4 分钟 · 745 字 · Wokron