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

系统编程之进程间通信

一、进程间通信简述 进程是程序的一次运行的动态过程,为了完成一个任务,很多进程之间需要进行通信,从而相互合作以实现需要的功能。操作系统内核中提供了进程间通信的方法,主要有以下几种: 管道: 管道是最基本的进程通信机制,可以想象成一个管道,两端分别连着 2 个进程,一个进程往里面写,一个进程从里面读。如果读或写管道的时候没有内容可供读或写,进程将被阻塞,直到有内容可供读写为止。 消息队列: 消息队列本质上在内核空间中开辟了一块内存空间,这块内存是其他进程可以访问到的,在其中使用链表的方式实现了一个队列,进程可以向该队列中发送数据块或读取数据块,从而达到进程间通信的目的。其中每个数据块包含两部分,首先是一个类型为 long 的 type,然后是具体的数据,数据块的 type 可以作为进程之间相互约定好的协议。例如一个进程发送 type 为123的消息,另一个进程接收 type 为123 的消息,后者便可确认这就是前者发送的信息,并信任该数据块中的数据。 信号量: 不同进程之间存在对资源的竞争,信号量就是用来标明可用资源的数量的数据结构,本质是为了实现多个进程之间的同步。需要注意,信号量(semaphore)与 “信号”(signal)没有关系。 共享内存: 共享内存的本质就是把两个或多个进程的虚拟地址映射到同一块物理内存。这样,一个进程通过对这块内存的读写就能被其他进程访问到,从而实现进程间通信的功能。 二、进程间通信操作 (1)准备操作 获取 key #include <sys/types.h> #include <sys/ipc.h> key_t ftok( const char * fname, int id ); 共享内存,消息队列,信号量等进程间通信方式都需要寻找一个中间介质来进行通信。不同的介质需要用不同的信息来进行区分,这就是进程间通信的 key。ftok() 函数就可以生成一个唯一的 key,该函数获取一个文件路径和一个字序号,生成一个用于区分的 key。 注意,选择文件路径只是因为文件的编号是独有的。设置的文件路径与代码和程序并没有什么关系。 命令管理进程间通信 若没有调用控制函数进行删除,则已分配的进程间通信不会自动释放。如果共享内存,消息队列,信号量在新进程执行时依旧有之前残留的信息,可能导致程序运行结果错误。可以通过 ipcs 和 ipcrm 命令进行管理。 ipcs # 显示所有进程间通信信息 ipcrm -q MsgID # 删除消息队列 ipcrm -s SemID # 删除信号量 ipcrm -m ShrID # 删除共享内存 (2)消息队列 消息队列获取 #include <sys/types....

十一月 16, 2022 · 5 分钟 · 962 字 · Wokron