最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Laravel代码简洁之道和性能优化

    正文概述 转载于:掘金(王中阳Go)   2021-07-12   572

    本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!

    • 经过一番调研之后发现了一个堪称神器的扩展:laravel-upsert
    • 这个 Laravel 扩展为查询构建器和 Eloquent 添加了对 INSERT & UPDATE (UPSERT) 和 INSERT IGNORE 的支持

    先简单说明一下业务场景:

    1. 首先表结构设计是:互相喜欢和添加联系人都是双向关系,即入库A B,B A这样成对的双向数据
    2. 触发互相喜欢,插入2条双向数据,插入之前校验是否存在,存在不重复添加
    3. 如果互相喜欢,则添加双向联系人关系,插入之前校验是否存在,存在则更新type等字段,不存在则插入双向数据

    优化代码前

        //校验是否存储
        public static function checkExist($userid, $otherUserid)
        {
            return self::query()
                ->where('userid', $userid)
                ->where('otherUserid', $otherUserid)
                ->exists();
        }
        
        //添加双向好友关系
        public static function addBoth($userid, $otherUserid)
        {
            if (!self::checkExist($userid, $otherUserid)) {
                UserRelationBoth::insert([
                    [
                        'userid' => $userid,
                        'otherUserid' => $otherUserid,
                        'createtime' => time(),
                        'updatetime' => time(),
                    ],
                    [
                        'userid' => $otherUserid,
                        'otherUserid' => $userid,
                        'createtime' => time(),
                        'updatetime' => time(),
                    ]
                ]);
    
                //互相喜欢,添加好友关系
                AppointmentContacts::saveContacts($userid, $otherUserid, AppointmentContacts::TYPE_RELATION_LIKE_EACHOTHER);
            }
        }
        
            //保存双向联系人
        public static function saveContacts($userid, $otherUserid, $type, $appointmentPrepareId = 0)
        {
            if (!self::checkExist($userid, $otherUserid)) {
                AppointmentContacts::insert([
                    [
                        'userid' => $userid,
                        'otherUserid' => $otherUserid,
                        'appointmentPrepareId' => 0,
                        'type' => $type,
                        'createtime' => time(),
                        'updatetime' => time(),
                    ],
                    [
                        'userid' => $otherUserid,
                        'otherUserid' => $userid,
                        'appointmentPrepareId' => 0,
                        'type' => $type,
                        'createtime' => time(),
                        'updatetime' => time(),
                    ]
                ]);
            } else {
                //存在更新状态
                self::updateContactsType($userid, $otherUserid, $type, $appointmentPrepareId);
            }
        }
        
         //更新最新关系类型
        public static function updateContactsType($userid, $otherUserid, $type, $appointmentPrepareId = 0)
        {
            self::query()
                ->where('userid', $userid)
                ->where('otherUserid', $otherUserid)
                ->update([
                    'type' => $type,
                    'appointmentPrepareId' => $appointmentPrepareId,
                    'updatetime' => time(),
                ]);
    
            self::query()
                ->where('userid', $otherUserid)
                ->where('otherUserid', $userid)
                ->update([
                    'type' => $type,
                    'appointmentPrepareId' => $appointmentPrepareId,
                    'updatetime' => time(),
                ]);
        }
    

    代码优化后

        public static function addBoth($userid, $otherUserid)
        {
            self::query()->insertIgnore([
                ["userid" => $userid, "otherUserid" => $otherUserid],
                ["userid" => $otherUserid, "otherUserid" => $userid]
            ]);
            //互相喜欢,添加好友关系
            AppointmentContacts::saveContacts($userid, $otherUserid, AppointmentContacts::TYPE_RELATION_LIKE_EACHOTHER);
        }
        
            //保存双向联系人
        public static function saveContacts($userid, $otherUserid, $type, $appointmentPrepareId = 0)
        {
            //没有添加 有则更新
            self::upsert([
                ["userid" => $userid, "otherUserid" => $otherUserid, 'type' => $type, "appointmentPrepareId" => $appointmentPrepareId],
                ["userid" => $otherUserid, "otherUserid" => $userid, 'type' => $type, "appointmentPrepareId" => $appointmentPrepareId]
            ],
                ['userid', 'otherUserid'],
                ['type' => $type, "appointmentPrepareId" => $appointmentPrepareId]
            );
        }
    

    优化效果

    代码量:优化前82行代码,优化后22行代码,代码行数少了3倍+

    查询sql的条数:优化前5条sql,优化后2条sql

    Laravel代码简洁之道和性能优化

    laravel-upsert 扩展的特性

    安装

    composer require staudenmeir/laravel-upsert:"^1.0"
    

    用法

    插入和更新 (UPSERT)

    考虑这个users具有唯一username列的表:

    Schema :: create ( 'users' , function ( Blueprint  $ table ) {
         $ table -> increments ( 'id' );
         $ table -> string ( 'username' )-> unique ();
         $ table -> boolean ( ' active' );
         $ table ->时间戳();
    });
    

    使用upsert()插入一个新的用户或更新现有的一个。在此示例中,将重新激活非活动用户并updated_at更新时间戳:

    DB :: table ( 'users' )-> upsert (
        [ 'username' => 'foo' , 'active' => true , 'created_at' => now (), 'updated_at' => now ()],
         'username' ,
        [ '活动','updated_at' ]
    );
    

    提供要作为第一个参数插入的值。这可以是单个记录或多个记录。

    第二个参数是唯一标识记录的列。除 SQL Server 外的所有数据库都要求这些列具有PRIMARY或UNIQUE索引。

    提供要更新的列作为第三个参数(可选)。默认情况下,将更新所有列。您可以提供带有文字或原始表达式的列名和键值对(见下文)。

    作为使用复合键和原始表达式的示例,请考虑以下表,该表计算每个帖子和每天的访问者:

    Schema :: create ( 'stats' , function ( Blueprint  $ table ) {
         $ table -> unsignedInteger ( 'post_id' );
         $ table -> date ( 'date' );
         $ table -> unsigned Integer ( 'views' );
         $表->主要([ 'post_id','date' ]);
    });
    

    使用upsert()登录访问。该查询将为每个帖子和日期创建一个新记录或增加现有的查看计数器:

    DB :: table ( 'stats' )-> upsert (
        [
            [ 'post_id' => 1 , 'date' => now ()-> toDateString (), 'views' => 1 ],
            [ 'post_id' => 2 , 'date' => now ()-> toDateString (), 'views' => 1 ],
        ],
        [ 'post_id','日期' ],
        [ 'views' => DB :: raw ( 'stats.views + 1' )]
    );
    

    插入忽略

    您还可以在忽略重复键错误的同时插入记录:

    Schema :: create ( 'users' , function ( Blueprint  $ table ) {
         $ table -> increments ( 'id' );
         $ table -> string ( 'username' )-> unique ();
         $ table -> timestamps () ;
    });
    
    DB :: table ( 'users' )-> insertIgnore ([
        [ 'username' => 'foo' , 'created_at' => now (), 'updated_at' => now ()],
        [ 'username' => 'bar' , 'created_at' => now (), 'updated_at' => now ()],
    ]);
    

    SQL Server 需要带有唯一标识记录的列的第二个参数:

    DB :: table ( 'users' )-> insertIgnore (
        [ 'username' => 'foo' , 'created_at' => now (), 'updated_at' => now ()],
         'username' 
    );
    
    

    Eloquent

    你可以在 Eloquent 模型中使用 UPSERT 和 INSERT IGNORE 查询。

    在 Laravel 5.5-5.7 中,这需要HasUpsertQueriestrait:

    class User extends Model
    {
        use \Staudenmeir\LaravelUpsert\Eloquent\HasUpsertQueries;
    }
    
    User::upsert(['username' => 'foo', 'active' => true], 'username', ['active']);
    
    User::insertIgnore(['username' => 'foo']);
    
    

    如果模型使用时间戳,upsert()并且insertIgnore()会自动为插入的值添加时间戳。upsert()还将添加updated_at到更新的列中。

    Lumen

    如果您使用 Lumen,则必须手动实例化查询构建器:

    $builder = new \Staudenmeir\LaravelUpsert\Query\Builder(app('db')->connection());
    
    $builder->from(...)->upsert(...);
    
    

    在 Eloquent 中,所有版本的 LumenHasUpsertQueries都需要该特性。

    注意的问题

    • 要根据需求添加唯一索引
    • 根据官方文档中的说明,我们的model中必须添加这行代码,才能以Eloquent的方式用
    use \Staudenmeir\LaravelUpsert\Eloquent\HasUpsertQueries;
    
    • 因为我们数据库的时间是int类型,不是laravel默认的时间格式,并且我们的插入时间和更新时间也不是laravel默认的字段,我们需要做如下定义:
        //时间戳类型
        public $timestamps = true;
    
        //重写插入和修改时间的字段名
        const CREATED_AT = 'createtime';
        const UPDATED_AT = 'updatetime';
        
        //设置日期格式为时间戳
        protected $dateFormat = 'U';
        
        //如果取值有使用toArray()转成数组的话还需要下方的配置
        //获得创建时间
        protected function getCreatetimeAttribute($value)
        {
            return intval($value);
        }
        //获得修改时间
        protected function getUpdatetimeAttribute($value)
        {
            return intval($value);
        }
    

    总结

    • 代码优化是一个不断优化的过程,好久没有更新文章啦,最近会更新一波代码简洁之道和性能优化的文章,包括代码方面的抽象设计、结构方面的、优秀的第三方扩展等。

    Laravel代码简洁之道和性能优化

    支持一波

    掘金的年中总结希望大家支持一下哈,欢迎点赞评论 93年程序员在帝都买房后,又开始思考怎样赚更多的钱了。|2021 年中总结


    起源地 » Laravel代码简洁之道和性能优化

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元