「拥抱开源」从零开始 Docker、Mysql & JPA
MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件之一。
世界上最昂贵的东西是“免费”。
为了降低项目成本,我们有一套完整的 MySQL 开源社区版集群。希望能在低成本的基础上,带来期望的收益。
然而,经过不停的填坑操作告诉我们一个道理。
“免费” === 无人维护,商业运用还是 Oracle 关系型数据库来的香。
01 背景
这里是凭爱发电的开源项目 oPos。
考虑到将来还要自己全栈做 dev-ops,为了不给自己挖太深的坑。本项目的数据库存储采用以下技术选型:
- Docker ✔︎
- MySQL ✔︎
-
Oracle✘
本文的主要作用是记录 MySQL 安装与 JPA 的建表操作过程。为以后的技术复盘、运维做准备。
PS.欢迎大家 star: https://github.com/FoamValue/oPos.git
02 Docker 安装
Docker 是个好工具。
它是一个开源的虚拟应用容器引擎。随着云计算、AI、大数据等技术浪潮下,可以自动化部署、运维成千上万台服务器的 Docker 容器与虚拟技术,成为一件新的技术“神器”。
个人使用非常简单,直接下载安装程序即可。
03 Docker 安装 MySQL
首先,我们使用 search 命令来感受下 Docker 的强大。
罗列了所有 MySQL 的版本,再也没有寻找安装包该在哪里下载的痛苦了。
商业项目建议使用相对稳定的老版本,例如 5.6、5.7。
但,既然是开源项目。那就勇猛直前的最新 latest 版本就好。顺便还能感受下新的版本特性。
下载完成之后,可以使用 images 命令查看本地的镜像版本。例如:mysql latest,zookeeper 3.4.14。
目前,还没有部署测试环境的概念。
所以,现在选用“不建立映射目录”的方式运行。也就是,存储数据会丢失。
使用 Navicat 配置 MySQL 的访问方式。
创建一个 utf8 编码格式的数据库 oPos。
到这里,一个名叫 oPos 的关系型数据库就创建好了。
04 JPA 配置
在国内使用 JPA 来操作数据库,这样的运用场景是非常少的。
- 历史原因,大量的老开发人员习惯于 iBatis 操作数据库的风格。
- MyBatis 的出现,继承了 iBatis 的基础上,又进行了大量的优化。
- 在商业运用中,大量的 SQL 查询需要手动干预进行优化。
虽然,有更优秀的操作数据库的解决方案。但是,JPA 真的就没有优点了吗?
答案当然是:我也不知道。
JPA 特别适合中小型项目,它能帮助后端开发工程师更好的理解数据设计,让后端开发工程师把更多的时间、精力放在代码设计与优化之上。
至于 SQL 查询的销量,就让 JPA 自身优化去吧。
首先,在项目中引入 JPA、mysql 依赖包。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
在 application-dev.yml 中增加数据库链接的配置。
spring:
profiles: dev
datasource:
jdbcUrl: jdbc:mysql://127.0.0.1:3306/oPos?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=true
username: root
password: 123456
driverClassName: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
hikari:
poolName: hikari-local
autoCommit: true
connectionTestQuery: SELECT 1
connectionTimeout: 30000
idleTimeout: 30000
maxLifetime: 1800000
maximumPoolSize: 5
minimumIdle: 1
jpa:
hibernate:
ddl-auto: update
show-sql: true
增加一个 MySQL 工厂与 Spring 事务配置类。
**
* Application config.
*
* @author chenxinjie
* @date 2020-08-01
*/
@Configuration
@EnableJpaRepositories
@EnableTransactionManagement
public class ApplicationConfig {
/**
* data source.
*
* @return
*/
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
/**
* entity manager factory.
*
* @return
*/
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("cn.live.opos");
factory.setDataSource(dataSource());
return factory;
}
/**
* transaction manager.
*
* @param entityManagerFactory manager factory.
* @return
*/
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory);
return txManager;
}
}
以上,JPA 操作数据库的配置就结束了。
05 JPA 创建表
上一节说到,JPA 可以帮助后段开发工程师更好的理解数据库设计,就体现这里。
以下是一张导购表的 JPA 实体 Java 类。
UscGuideEntity 使用了大量的 javax.persistence.* 注解进行修饰,这样的目的是在应用启动的过程中,程序会主动的像数据库中创建指定的表。
/**
* usc_guide.
*
* @author chenxinjie
* @date 2020-08-01
*/
@Entity
@Table(name = "usc_guide", uniqueConstraints = { @UniqueConstraint(columnNames = "no") })
public class UscGuideEntity {
private static final long serialVersionUID = -5648617800765002770L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid2")
@Column(name = "id", length = 32)
private String id;
@Column(name = "no", length = 20, nullable = false)
private String no;
@Column(name = "name", length = 40, nullable = false)
private String name;
@Column(name = "gender", columnDefinition = "int default 0", nullable = false)
private int gender;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "ts", columnDefinition = "timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP() ON UPDATE CURRENT_TIMESTAMP()", nullable = false)
private Date ts;
public final String getId() {
return id;
}
public final void setId(String id) {
this.id = id;
}
public final String getNo() {
return no;
}
public final void setNo(String no) {
this.no = no;
}
public final String getName() {
return name;
}
public final void setName(String name) {
this.name = name;
}
public final int getGender() {
return gender;
}
public final void setGender(int gender) {
this.gender = gender;
}
public final Date getTs() {
return ts;
}
public final void setTs(Date ts) {
this.ts = ts;
}
public static final long getSerialversionuid() {
return serialVersionUID;
}
}
使用 Java 类来创建数据库表,这样的方式。将数据库表对象化,让后端开发人员非常的舒服。
当然,JPA 并不仅仅如此。它还有更加贴合手动建表的配置方式,例如:
1. 指定表名、唯一约束:
@Table(name = "usc_guide", uniqueConstraints = { @UniqueConstraint(columnNames = "no") })
2. 程序自动生成主键:
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid2")
@Column(name = "id", length = 32)
private String id;
3. 字段长度、是否为空,等自定义配置:
@Column(name = "gender", columnDefinition = "int default 0", nullable = false)
4. 时间戳配置:
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "ts", columnDefinition = "timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP() ON UPDATE CURRENT_TIMESTAMP()", nullable = false)
private Date ts;
5. 懒加载的一对多、多对多、一对一等配置:
@OneToMany(cascade = { CascadeType.REFRESH, CascadeType.PERSIST, CascadeType.MERGE,
CascadeType.REMOVE }, fetch = FetchType.LAZY, mappedBy = "orderEntity")
private Set<OscOrderItemEntity> orderItems;
@OneToOne
@JoinColumn(name = "sku", referencedColumnName = "sku", insertable = false, updatable = false)
private PscSkuEntity skuEntity;
6. 不挑数据库、换个数据库配置,就能自动建表。
7. 等等
06 小结
今天先写到这里。
夜深了,让我们下周再见。?
这个周末,又一次成功“强迫”自己学习。
感谢各位小伙伴的阅读,这里是一个技术人的学习与分享。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 基于python实现计算两组数据P值
- PHP getNamespaces()函数讲解
- OpenCV 使用imread()函数读取图片的六种正确姿势
- PHP simplexml_import_dom()函数讲解
- PHP getName()函数讲解
- Laravel框架集成UEditor编辑器的方法图文与实例详解
- PHP+redis实现的购物车单例类示例
- ThinkPHP3.2.3框架邮件发送功能图文实例详解
- PHP simplexml_load_file()函数讲解
- Python下划线5种含义代码实例解析
- PHP getDocNamespaces()函数讲解
- Django实现内容缓存实例方法
- Tensorflow–取tensorf指定列的操作方式
- spring-boot-route(一)Controller接收参数的几种方式
- python中 _、__、__xx__()区别及使用场景