欢迎来到腾讯云+社区获取更多腾讯海量技术实践的干货~本文由horstxu发表于云+社区专栏一、问题背景PHPLaravel框架数据库迁移是一个比较常用的功能。在每次版本迭代中,除了代码的变化,一般数据库的字段或数据库表也会有一些变化。因此,新版本上线时,除了发布新版本的代码外,不可避免的还要对数据库进行改动。在db迁移功能之前,我们的方法是把改变数据库表的sql语句(CREATETABLE,ALTERTABLE等)写在一个sql文件里,然后上线的时候连接数据库,执行一次sql语句.这样做的一个比较大的缺点就是没有数据库的版本管理。万一上线失败,需要回滚版本,sql文件的内容一定要写反向SQL(DROPTABLE,DROPCOLUMN等)。这种方法也比较原始。在web开发中,我们总是希望尽可能避免直接使用原始SQL来操作数据库。出错的风险很高,很可能会出现不可逆的错误,所以我们每次操作都要谨慎。于是乎,PHPLaravel框架提供了db迁移的功能,使用代码来管理数据库。参考链接2.问题描述在新版本中,我通过以下方式记录我的数据库变化:phpartisanmake:migrationdb_migration_for_new_version这样会在项目的database/migrations目录下新建一个PHP文件,并填写需要的Changed数据库内容publicfunctionup{Schema::create('a_new_table',function(Blueprint$table){$table->bigIncrements('id');});Schema::create('another_new_table',function(Blueprint$table){$table->bigIncrements('id');$table->string('user',64)->default(0)->comment('username');//这里模拟出现错误的情况thrownew\Exception("Anerroroccurred");});}上面的例子,我的初衷是创建两张表。但是,第一张表创建完成后,第二张表出错,创建失败。按照正常的流程,我上线的时候应该执行下面的命令来创建表单phpartisanmigrate由于第二个表单的创建失败,此时上面的命令必然会报错。但是报错之后怎么办呢?首先当然是更正代码中的错误,然后怎么办呢?此时数据库中的第一张表已经建好,但是第二张表还没有建好。这时候再执行phpartisanmigrate会报错:你的第一张表已经创建好了,不能重复创建表。你可能觉得我需要回滚一次,所以你可能会进行回滚操作phpartisanmigrate:rollback--step=1。这里需要强调一下,这个时候不要回滚!!!因为刚才第一次执行migration时出错,导致数据库没有生成新的版本号。如果此时回滚,你将回滚的是上一个版本发布时的数据库操作,而不是你刚刚执行的这个版本的数据库操作。这可能是灾难性的,会导致您的数据丢失。最新版本的数据库是多少,可以参考数据库中migrations表的batch字段(这个表是laravel迁移功能自动生成管理的,不是业务表)。总结一下这个无解的深坑:db迁移中途出错。此时只能手动操作数据库回滚已经执行过的操作,不能再通过artisan命令进行回滚。3、为什么没有解决办法?其实在GitHub和StackOverflow上很多人都遇到过这个问题,但是答案都很悲观。大家的第一反应是:可以开始交易操作了吗?是否可以将迁移的所有操作视为一个整体,要么成功要么失败?不幸的是,不支持事务操作。在mysql中,事务只有在执行update、insert、delete等常规操作时才能执行,而我们迁移中执行的所有操作都是DDL(DataDefinitionLanguage)操作。这种创建表(CREATETABLE)和修改表结构(ALTERTABLE)的操作是不能回滚的,即使打开了事务(参考链接)。将DDL操作放在事务(Transaction)中会导致事务自动提交(参考链接),这往往不是我们代码逻辑所期望的结果。4.那怎么办?如果你已经遇到过这种问题,那你就只能自己去手动查看数据库中发生了什么变化,然后自己进行逆向操作。只有几种方法可以防止此问题发生。根据GitHub上的开发者建议,最好将每个CREATETABLE和ALTERTABLE操作单独迁移。即每次迁移只建一个表,或者只改变一个表结构,只执行一个操作(参考链接)...另一种方式是将自己的建表和修改表操作放在一个trycatch结构中,一旦出错,直接调用迁移文件中的down函数回滚操作。但是,这需要注意上下兼容。比如up有一个ADDCOLUMN操作,down有一个DROPCOLUMN操作。如果在执行ADDCOLLUMN操作之前出现错误,如果直接执行down函数中的DROPCOLUMN,也可能会报COLUMN不存在的错误。总之,这个问题没有完美的解决办法,堪称无解的坑。尤其要注意不要乱做回滚操作,不要为了补个坑给自己挖更大的坑。问答PHP功能滥用?相关阅读一张图看懂ASCII、GB2312、GBK、GB18030编码其实csv文件格式你未必懂【每日课程推荐】机器学习实战!快速入门网络广告业务及CTR对应知识本文已获作者授权腾讯云+社区发布。更多原创文章请点击搜索关注公众号「云+社区」,第一时间获取技术干货,关注后回复1024为您送上技术课程大礼包!海量技术实战经验,尽在云家社区!
