ORM
ORM(Object Relational Mapping,对象关系映射),作用是在关系型数据库和对象之间作一个映射。
1 | 数据表 <--> 类 |
GROM入门
详细内容查看GORM文档
连接数据库
1 | package main |
ORM(Object Relational Mapping,对象关系映射),作用是在关系型数据库和对象之间作一个映射。
1 | 数据表 <--> 类 |
详细内容查看GORM文档
1 | package main |
Gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。这个钩子函数就叫中间件,中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等。
Gin的中间件必须是一个gin.handlerFunc
类型type HandlerFunc func(*Context)
。
1 | // TimeCost是一个统计请求耗时的中间件 |
使用FormFile
方法可以获取到POST请求中上传的文件:
1 | func main() { |
请求头参数设置 Content-Type: multipart/form-data
,多文件上传请求为:
1 | curl -X POST http://localhost:8080/upload \ |
首先解析 multipart forms,然后获取文件列表。
1 | func main() { |
使用Redirect
方法即可进行HTTP重定向:
1 | r.GET("/index", func(c *gin.Context) { |
通过 POST 方法进行 HTTP 重定向(这里可以使用 StatusMovedPermanently 301 状态码、StatusFound 302 状态码和 StatusSeeOther 303 状态码)。
1 | r.POST("/test", func(c *gin.Context) { |
303 状态码明确表示客户端应当采用 GET 方法获取资源,这点与 302 状态码有区别。
当 301、302、303 响应状态码返回时,几乎所有的浏览器都会把 POST 改成 GET,并删除请求报文内的主体,之后请求会自动再次发送。301、302 标准是禁止将 POST 方法改变成 GET 方法的,但实际使用时大家都会这么做。
首先编写模板文件index.tmpl
:
1 | <!DOCTYPE html> |
Gin中使用LoadHTMLGlob()
或者LoadHTMLFiles()
进行模板渲染:
1 | package main |
Gin是一个由Go语言编写的高性能Web框架。
1 | package main |
REST,即Representational State Transfer,表现层状态转化。RESTful架构:
Gin框架支持开发RESTful API的开发:
1 | func main() { |
多版本并发控制(Multi-Version Concurrency Control,MVCC),通过数据行的多个版本管理来实现数据库的并发控制。
在MySQL中,可重复读是默认的隔离级别。可重复读隔离级别下,不仅解决了脏读和不可重复读问题,因为使用了MVCC,所以还一定程度上解决了幻读的问题。
快照读又叫一致性读,读取的是快照数据。不加锁的简单的SELECT语句,都属于快照读。
之所以出现快照读的情况,是基于提高并发性能的考虑,快照读的实现是基于MVCC,它在很多情况下,避免了加锁操作,降低了开销。既然是基于多版本,那么快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本。
当前读读取的是记录的最新版本的数据,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。加锁的SELECT语句,以及对数据进行增删改都会进行当前读。
利用动态规划,dp[i]
表示金额为i
的硬币组合数,边界条件是dp[0] = 1
,表示组成金额0
有一种组合数。
dp[0] = 1
coins
,对于其中的每个元素coin
:i
从coin
到amount,dp[i] += dp[i-coin]
dp[amount]
为最终答案1 | func change(amount int, coins []int) int { |
MySQL中利用锁来保证事务的隔离性,对并发操作进行控制。同时,锁冲突也是影响数据库并发访问性能的重要因素。
对于两个事务都进行写数据(写-写情况)的操作,可能会产生脏写问题,这是任何一种隔离级别都不允许这种问题的发生的。
所以在多个未提交事务相继对一条记录做改动时,需要让它们排队执行(通过锁实现)。
对于一个事务进行读取操作,一个事务进行写数据的操作(读-写情况),可能会产生脏读、不可重复读和幻读的问题。对于这些问题,有两种解决方案。
所谓MVCC,就是生成一个ReadView,通过ReadView找到符合条件的记录版本。查询语句只能读到生成ReadView之前已提交事务所做的更改。而写操作肯定针对的是最新的版本信息,读记录的历史版本和改动记录的最新版本并不冲突,也就是采用MVCC时,读-写并不冲突。
普通的SELECT语句在READ COMMITTED
和REPEATABLE READ
隔离级别下会使用到MVCC读取记录:
READ COMMITTED
隔离级别下,一个事务在执行过程中每次执行SELECT操作时都会生成一个ReadView,ReadView的存在本身就保证了事务不可以读取到未提交的事务所做的更改,也就是避免了脏读现象。REPEATABLE READ
隔离级别下,一个事务在执行过程中只有第一次执行SELECT操作才会生成一个ReadView,之后的SELECT操作都复用这个ReadView,这样也就避免了不可重复读和幻读的问题。