programing

Laravel - my Web services Api를 여러 번 호출하면 데이터베이스의 단일 항목과 데이터베이스의 복제 기록 논리를 무시합니다.

magicmemo 2023. 9. 8. 21:21
반응형

Laravel - my Web services Api를 여러 번 호출하면 데이터베이스의 단일 항목과 데이터베이스의 복제 기록 논리를 무시합니다.

웹 서비스를 가지고 있습니다. API는 데이터베이스에 여러 번 데이터를 삽입하지만 기록이 존재할 경우 한 번삽입하고 두 번째업데이트하면 됩니다.

트랜잭션으로 인해 문제가 발생했습니다.여기서 무슨 일이 일어나고 있는지 다 설명해 드렸습니다.

Laravel 5.4 데이터베이스:Maria Db 10.1.21 호스트: 로컬 호스트

웹 서비스 포함

  • 결과를 가져오기 위해 외부 apis 호출
  • 데이터베이스에 가져오기 결과 저장

// 코드를 여기에

   public function getWebsiteDetails(Request $request) {
    Log::info("call ");
    try 
    {
     return DB::transaction(function () use($request)  
    {

    //  Get record from website_master of given business id
    $businessWebsiteRecord = Website::where([
        'business_id' => $businessId
    ])->first();

    // calling external api to get result
    $pageSpeedResult = $this->pageSpeedResult($url);

    Log::info("crossed external api point");

    /**
     * Again check to confirm record is exist or not
     * code write to only for testing purpose
     */
    $recordChecker = Website::where
    (
        'business_id', $businessId
    )->first();

    if(!empty($recordChecker))
    {
    Log::info("if" );
    }
    else
    {
    Log::info("else");
    }

    /**
    * Update record if exist
    * else
    * Create record
    */
    Website::updateOrCreate(
    ['business_id' => $businessId],
    [
    'website' => $url
    ]
    );

    // saving data in another table after some operatins
    $thirdObj->globalIssueGenerator(/* some data*/);

    return $this->helpReturn('Website data saved & issues are generated in system');
    });

    } catch (Exception $e) {
    Log::info(" getWebsiteDetails >> " . $e->getMessage());
    return $this->helpError(1, 'Some Problem happened to run script.');
    }
    }

데이터베이스 테이블에 한 행 항목만 추가해야 합니다.그러나 문제는 api를 여러호출하면 데이터베이스데이터를 여러삽입하고 처음/단일 시간만 추가하면 된다는 것입니다.애즈 라라벨Updateorcreate함수가 사용중입니다.

테스트 케이스

내가 처음으로 API를 호출한 후 3-5초 후에 다시 API를 두 번째로 누르면 됩니다.

해당 api는 체크를 생략하고 삽입 데이터와 같은 데이터를 이 스크린샷과 같이 여러 번 다시 삽입합니다.

enter image description here

그래서 아래 코드로 확인하는 겁니다.

/**
* Again check to confirm record is exist or not
* code write to only for testing purpose
*/

$recordChecker = Website::where
('business_id', $businessId)->first();

if(!empty($recordChecker))
{
Log::info("if");
}
else
{
Log::info("else");
}

로그:

로그는 데이터베이스 삽입 스크린샷에서와 동일한 시간에 생성되었습니다.

[2018-02-12 06:18:58] local.INFO: call   
[2018-02-12 06:19:03] local.INFO: call   
[2018-02-12 06:19:16] local.INFO: crossed external api point

데이터베이스에서 데이터를 사용할 수 없기 때문에 다른 방법으로 들어갑니다.

[2018-02-12 06:19:16] local.INFO: else

스크린샷 데이터가 데이터베이스에 삽입되었습니다.

두 번째 통화 로그

[2018-02-12 06:19:19] local.INFO: else
[2018-02-12 06:19:19] local.INFO: crossed external api point

데이터가 아직 데이터베이스에 없기 때문에 다시 다른 곳으로 들어갑니다.

데이터베이스에서 데이터를 제출했지만 두 번째 통화 응답이 진행 중입니다.

문제 탐지:

트랜잭션을 사용하고 있습니다. 레코드를 삽입/업데이트하여 두 개의 테이블을 업데이트하고 있습니다.

거래없음 거래코드를 댓글로 달아서 위의 테스트 케이스 데이터를 적용하면 한 번만 삽입됩니다.내가 요구하는 것.

여기 거래가 없는 곳의 기록이 있습니다.

[2018-02-12 06:59:56] local.INFO: call   
[2018-02-12 07:00:00] local.INFO: call   
[2018-02-12 07:00:14] local.INFO: crossed external api point  

데이터베이스에서 데이터를 사용할 수 없기 때문에 데이터가 생성되므로 다른 방법으로 들어갑니다.

[2018-02-12 07:00:14] local.INFO: else  

[2018-02-12 07:00:17] local.INFO: crossed external api point  

데이터베이스에서 사용 가능한 데이터 때문에 들어가는 경우

[2018-02-12 07:00:17] local.INFO: if  

하지만 첫 번째 테이블에 데이터를 삽입한 후 대부분의 작업을 수행하고 테이블에 여러 개의 데이터를 삽입하기 때문에 트랜잭션을 제거할 수 없습니다.

파일 시스템이나 Redis에서 플래그를 업데이트하기 위해 다른 작업을 사용하려고 생각하고 있습니다만, 그것은 다른 기술입니다.나는 이것을 처리할께요.

같은 기술을 사용하는 웹 서비스가 더 많기 때문에 이 문제를 해결할 수 있는 사람이 있으면 좋겠습니다.

FULL Code

public function getWebsiteDetails(Request $request)
    {
        Log::info("call ");
        try {
            return DB::transaction(function () use($request)
            {
                $thirdObj = new ThirdPartyEntity();

                // user extract
                $checkPoint = $this->setCurrentUser($request->get('token'))->userAllow();

                $user = $checkPoint['records'];
                $businessDetail = $this->businessEntity->userSelectedBusiness($user);

                $businessDetail = $businessDetail['records'];

                $userId = $user['id'];
                $businessId = $businessDetail['business_id'];
                $url = $businessDetail['website'];

                /**
                 * Get record from website_master of given business id
                 */
                $businessWebsiteRecord = Website::where([
                    'business_id' => $businessId
                ])->first();

                // if business_master (url) is exist then go to if block
                if ($url != '') {
                    $data = [];

                        $pageSpeedScore = '';
                        $mobileReadyScore = '';
                        $data['website'] = $url;

                        $url = 'http://'.$url;
                        $pageSpeedResult = $this->pageSpeedResult($url);


                        if( $pageSpeedResult['_metadata']['outcomeCode'] == 200 )
                        {
                            $pageSpeedData = $pageSpeedResult['records'];

                            $speedResult = json_encode($pageSpeedData['formattedResults']['ruleResults']);

                            $data['title_tag'] = $pageSpeedData['title'];
                            $data['page_speed_score'] = $pageSpeedData['score'];
                            $data['page_speed_suggestion'] = $speedResult;

                            $pageSpeedScore = $pageSpeedData['score'];
                        }
                        else
                        {
                            $speedResult = NULL;

                            $data['title_tag'] = NULL;
                            $data['page_speed_score'] = NULL;
                            $data['page_speed_suggestion'] = NULL;
                        }

                    $mobileFriendlyResult = NULL;

                    $data['mobile_ready_score'] = 0;
                    $data['mobile_ready'] = 0;
                    $data['mobile_ready_suggestion'] = NULL;

                    $data['google_analytics'] = 0;

                        Log::info("busnes " . $businessId);
                        Website::updateOrCreate(
                            ['business_id' => $businessId],
                            $data
                        );

                    $issueData = []
                        $thirdObj->globalIssueGenerator($userId, $businessId, '', $issueData, 'website', 'website');


                    return $this->helpReturn('Website data saved & issues are generated in system');
                }
            });

        } catch (Exception $e) {
            Log::info(" getWebsiteDetails >> " . $e->getMessage());
            return $this->helpError(1, 'Some Problem happened to run script.');
        }
    }

거래 중 레코드 잠금을 사용하여 레코드 중복을 방지합니다.

잠금은 테이블 레벨에서 적용할 수 있습니다. - 레코드를 수정할 수 없도록 - 또는 레코드 레벨에서 - 다른 프로세스에서 해당 레코드만 수정할 수 없도록 합니다.

중복 항목이 있으므로 테이블 레벨 잠금을 사용해야 할 수 있습니다.

@btl, @니콜라

현재 코드 위치 변경 및 결과를 올바르게 반환하고 데이터베이스에 레코드를 삽입하여 시도하고 있습니다.

데이터베이스에 체크 데이터가 있는지 없는지 트랜잭션 코드를 붙여넣습니다.현재 무슨 일이 일어나고 있는지 파악하고 있지만 현재 상태를 공유하고 있습니다. 새 코드와 이전 코드를 참조하십시오.새로운 코드가 작동중이고 또한 두 코드의 로그를 추가합니다.

변경후새코드

public function getWebsiteDetails(Request $request)
    {
        Log::info("call ");
        try {

            /**
             * out from transction
             */
            // extract user 
            $checkPoint = $this->setCurrentUser($request->get('token'))->userAllow();

            $user = $checkPoint['records'];

            // extract business of user
            $businessDetail = $this->businessEntity->userSelectedBusiness($user);

            $businessDetail = $businessDetail['records'];
            $userId = $user['id'];
            $businessId = $businessDetail['business_id'];
            $url = $businessDetail['website'];

            /**
             * Get record from website_master of given business id
             */
            $businessWebsiteRecord = Website::where([
                'business_id' => $businessId
            ])->first();

            $result = DB::transaction(function () use($request, $url, $businessId, $userId,$businessWebsiteRecord)
            {
                $thirdObj = new ThirdPartyEntity();

                // if business_master (url) is exist then go to if block
                if ($url != '') {
                    $data = [];
                    $pageSpeedScore = '';
                    $mobileReadyScore = '';
                    $data['website'] = $url;
                    $url = 'http://' . $url;

                    $pageSpeedResult = $this->pageSpeedResult($url);

                    if ($pageSpeedResult['_metadata']['outcomeCode'] == 200) {
                        $pageSpeedData = $pageSpeedResult['records'];
                        $speedResult = json_encode($pageSpeedData['formattedResults']['ruleResults']);
                        $data['title_tag'] = $pageSpeedData['title'];
                        $data['page_speed_score'] = $pageSpeedData['score'];
                        $data['page_speed_suggestion'] = $speedResult;
                        $pageSpeedScore = $pageSpeedData['score'];
                    } else {
                        $speedResult = NULL;
                        $data['title_tag'] = NULL;
                        $data['page_speed_score'] = NULL;
                        $data['page_speed_suggestion'] = NULL;
                    }

                    $mobileFriendlyResult = NULL;
                    $data['mobile_ready_score'] = 0;
                    $data['mobile_ready'] = 0;
                    $data['mobile_ready_suggestion'] = NULL;
                    $data['google_analytics'] = 0;
                    Log::info("busnes " . $businessId);

                    $recordChecker = Website::where('business_id', $businessId)->first();

                    if (!empty($recordChecker)) {
                        Log::info("if busnes " . $businessId);
                    } else {
                        Log::info("else busnes " . $businessId);
                    }

                    Website::updateOrCreate(
                        ['business_id' => $businessId],
                        [
                            'website' => $url
                        ]
                    );
                    $issueData = [
                        [
                            'key' => 'title_tags',
                            'value' => $data['title_tag'],
                            'issue' => 36,
                        ],
                        [
                            'key' => 'page_speed',
                            'value' => $pageSpeedScore,
                            'issue' => 38,
                        ],
                        [
                            'key' => 'mobile_speed',
                            'value' => $mobileReadyScore,
                            'issue' => 37,
                        ],
                        [
                            'key' => 'google_analytics',
                            'value' => $data['google_analytics'],
                            'issue' => 39,
                        ]
                    ];
                    $thirdObj->globalIssueGenerator($userId, $businessId, '', $issueData, 'website', 'website');
                    return $this->helpReturn('Website data saved & issues are generated in system');
                }
            });

            Log::info("finish");
            return $result;

        } catch (Exception $e) {
            Log::info(" getWebsiteDetails >> " . $e->getMessage());
            return $this->helpError(1, 'Some Problem happened to run script.');
        }
    }

구코드

public function getWebsiteDetails(Request $request)
    {
        Log::info("call ");
        try {
            return DB::transaction(function () use($request)
            {
                $thirdObj = new ThirdPartyEntity();

                // user extract
                $checkPoint = $this->setCurrentUser($request->get('token'))->userAllow();

                $user = $checkPoint['records'];
                $businessDetail = $this->businessEntity->userSelectedBusiness($user);

                $businessDetail = $businessDetail['records'];

                $userId = $user['id'];
                $businessId = $businessDetail['business_id'];
                $url = $businessDetail['website'];

                /**
                 * Get record from website_master of given business id
                 */
                $businessWebsiteRecord = Website::where([
                    'business_id' => $businessId
                ])->first();

                // if business_master (url) is exist then go to if block
                if ($url != '') {
                    $data = [];

                        $pageSpeedScore = '';
                        $mobileReadyScore = '';
                        $data['website'] = $url;

                        $url = 'http://'.$url;
                        $pageSpeedResult = $this->pageSpeedResult($url);


                        if( $pageSpeedResult['_metadata']['outcomeCode'] == 200 )
                        {
                            $pageSpeedData = $pageSpeedResult['records'];

                            $speedResult = json_encode($pageSpeedData['formattedResults']['ruleResults']);

                            $data['title_tag'] = $pageSpeedData['title'];
                            $data['page_speed_score'] = $pageSpeedData['score'];
                            $data['page_speed_suggestion'] = $speedResult;

                            $pageSpeedScore = $pageSpeedData['score'];
                        }
                        else
                        {
                            $speedResult = NULL;

                            $data['title_tag'] = NULL;
                            $data['page_speed_score'] = NULL;
                            $data['page_speed_suggestion'] = NULL;
                        }

                    $mobileFriendlyResult = NULL;

                    $data['mobile_ready_score'] = 0;
                    $data['mobile_ready'] = 0;
                    $data['mobile_ready_suggestion'] = NULL;

                    $data['google_analytics'] = 0;

                        Log::info("busnes " . $businessId);
                        Website::updateOrCreate(
                            ['business_id' => $businessId],
                            $data
                        );

                    $issueData = []
                        $thirdObj->globalIssueGenerator($userId, $businessId, '', $issueData, 'website', 'website');


                    return $this->helpReturn('Website data saved & issues are generated in system');
                }
            });

        } catch (Exception $e) {
            Log::info(" getWebsiteDetails >> " . $e->getMessage());
            return $this->helpError(1, 'Some Problem happened to run script.');
        }
    }

참고: 데이터베이스에서 데이터를 사용할 수 없기 때문에 다른 데이터로 들어가므로 데이터가 이미 존재하기 때문에 데이터가 생성됩니다.(그것이 제가 얻은 것입니다)

네코드 로그

[2018-02-12 14:18:49] local.INFO: call   
[2018-02-12 14:18:53] local.INFO: call
[2018-02-12 14:19:08] local.INFO: crossed external api point
[2018-02-12 14:19:08] local.INFO: else
[2018-02-12 14:19:08] local.INFO: finish
[2018-02-12 14:19:09] local.INFO: crossed external api point
[2018-02-12 14:19:09] local.INFO: if
[2018-02-12 14:19:09] local.INFO: finish

이전 코드 로그

[2018-02-12 14:17:16] local.INFO: call   
[2018-02-12 14:17:19] local.INFO: call
[2018-02-12 14:17:34] local.INFO: crossed external api point
[2018-02-12 14:17:34] local.INFO: else
[2018-02-12 14:17:34] local.INFO: finish
[2018-02-12 14:17:35] local.INFO: crossed external api point
[2018-02-12 14:17:36] local.INFO: else
[2018-02-12 14:17:36] local.INFO: finish  

현재 첫 번째 트랜잭션실행되는 이전 로그에 따르면 이전 코드는 두 번째 트랜잭션에서 데이터베이스에서 아직 레코드를 찾지 못했지만 새 코드 로그에는 두 번째 트랜잭션을 시작하기 전의 데이터가 데이터베이스에서 발견된 데이터를 표시합니다.

네, 실패할 가능성이 있지만 응답이 같고 둘 다 동시에 데이터를 데이터베이스에 저장하는 경우에는 다른 기술을 사용할 것입니다. 하지만 이전 코드에서 실패하고 있던 3-5초 전에 레코드가 이미 삽입된 경우 새 코드가 레코드를 추적할 수 있는 더 좋은 기회를 가집니다.

고마워요 @btl and @Nikola.하지만 이 행동에 대한 내용이 있으면 공유해주세요.

언급URL : https://stackoverflow.com/questions/48745279/laravel-calling-my-web-services-api-multiple-times-bypass-the-logic-of-single

반응형