Бул эскизди жазууга макала түрткү болду
Ошол эле ой кызык көрүндү - "маалымат базасында бизнес логикасын ишке ашыруу".
Мен эле оюма келген жокмун.
Ошондой эле, келечекте, мен, биринчи кезекте, өзүм үчүн, ишке ашыруу учурунда пайда болгон кызыктуу окуяларды сактап калгым келди. Айрыкча, салыштырмалуу жакында эле архитектураны өзгөртүү жана бизнес-логиканы бэкенддик деңгээлге өткөрүү боюнча стратегиялык чечим кабыл алынганын эске алганда. Ошентип, иштелип чыккандын бардыгы жакында эч кимге пайдасыз жана эч кимди кызыктырбай калат.
сүрөттөлгөн ыкмалар кандайдыр бир ачылыш же өзгөчө эмес. технология, баары классикалык жана бир нече жолу ишке ашырылган (мисалы, мен 20 жыл мурун Oracleда ушундай ыкманы колдонгом) Мен жөн гана баарын бир жерге чогултууну чечтим. Эгер кимдир бирөө үчүн пайдалуу болсо. Практика көрсөткөндөй, бир эле идея ар кандай адамдарга өз алдынча келет. Ал эми аны сувенир катары өзүңүзгө сактоо пайдалуу.
Албетте, бул дүйнөдө эч нерсе идеалдуу эмес, каталар жана каталар, тилекке каршы, мүмкүн. Сын-пикирлер жана сын-пикирлер катуу кабыл алынат жана күтүлөт жана дагы бир майда-чүйдөсүнө чейин - конкреттүү ишке ашыруу деталдары калтырылган. Ошентсе да, баары дагы эле чыныгы жумушчу долбоордо колдонулат. Демек, макала жөн гана эскиз жана жалпы түшүнүктүн сүрөттөлүшү, башка эч нерсе эмес. Мен жалпы сүрөттү түшүнүү үчүн жетиштүү маалымат бар деп үмүттөнөм.
Жалпы идея "бөлүп ал жана жең, жашын жана ээлик кыл"
Идея классикалык - таблицалар үчүн өзүнчө схема, сакталган функциялар үчүн өзүнчө схема.
Кардар маалыматтарга түздөн-түз кире албайт. Кардар сакталган функцияны чакырып, кабыл алынган жоопту иштете алат.
ролу
CREATE ROLE store;
CREATE ROLE sys_functions;
CREATE ROLE loc_audit_functions;
CREATE ROLE service_functions;
CREATE ROLE business_functions;
схемалары
Стол сактоо схемасы
Предметтик объекттерди ишке ашыруучу максаттуу таблицалар.
CREATE SCHEMA store AUTHORIZATION store ;
Системанын иштешинин диаграммасы
Системалык функциялар, атап айтканда, таблицадагы өзгөрүүлөрдү каттоо үчүн.
CREATE SCHEMA sys_functions AUTHORIZATION sys_functions ;
Жергиликтүү аудит схемасы
Сакталган функциялардын аткарылышынын жергиликтүү аудитин жана максаттуу таблицаларга өзгөртүүлөрдү киргизүү үчүн функциялар жана таблицалар.
CREATE SCHEMA loc_audit_functions AUTHORIZATION loc_audit_functions;
Кызмат функциясынын диаграммасы
Кызмат жана DML функциялары үчүн функциялар.
CREATE SCHEMA service_functions AUTHORIZATION service_functions;
Бизнес-функция диаграммасы
Кардар чакырган акыркы бизнес функциялары үчүн функциялар.
CREATE SCHEMA business_functions AUTHORIZATION business_functions;
Кирүү укугу
Рол - DBAs бардык схемаларга толук мүмкүнчүлүгү бар (МБ Ээсинин ролунан бөлүнгөн).
CREATE ROLE dba_role;
GRANT store TO dba_role;
GRANT sys_functions TO dba_role;
GRANT loc_audit_functions TO dba_role;
GRANT service_functions TO dba_role;
GRANT business_functions TO dba_role;
Рол - КОЛДОНУУЧУ артыкчылыкка ээ АТКАРУУ диаграммада бизнес_функциялары.
CREATE ROLE user_role;
Схемалардын ортосундагы артыкчылыктар
ГРАНТ
Анткени бардык функциялар атрибут менен түзүлгөн КООПСУЗДУКТУ АНЫКТООЧУ керектүү көрсөтмөлөр БАРДЫК ФУНКЦИЯЛАРДА АТКАРЫЛУУНУ ЖОГОРКУ АЛУУ… ачыктан;
REVOKE EXECUTE ON ALL FUNCTION IN SCHEMA sys_functions FROM public ;
REVOKE EXECUTE ON ALL FUNCTION IN SCHEMA loc_audit_functions FROM public ;
REVOKE EXECUTE ON ALL FUNCTION IN SCHEMA service_functions FROM public ;
REVOKE EXECUTE ON ALL FUNCTION IN SCHEMA business_functions FROM public ;
GRANT USAGE ON SCHEMA sys_functions TO dba_role ;
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA sys_functions TO dba_role ;
GRANT USAGE ON SCHEMA loc_audit_functions TO dba_role ;
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA loc_audit_functions TO dba_role ;
GRANT USAGE ON SCHEMA service_functions TO dba_role ;
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA service_functions TO dba_role ;
GRANT USAGE ON SCHEMA business_functions TO dba_role ;
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA business_functions TO dba_role ;
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA business_functions TO user_role ;
GRANT ALL PRIVILEGES ON SCHEMA store TO GROUP business_functions ;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA store TO business_functions ;
GRANT USAGE ON ALL SEQUENCES IN SCHEMA store TO business_functions ;
Ошентип, маалымат базасынын схемасы даяр. Сиз маалыматтарды толтуруп баштаса болот.
Максаттуу таблицалар
Таблицаларды түзүү анча маанилүү эмес. Эч кандай өзгөчө функциялар, аны колдонбоо чечими кабыл алынганын эске албаганда СЕРИЯ жана ырааттуулукту ачык генерациялайт. Plus, албетте, көрсөтмөлөрдү максималдуу пайдалануу
COMMENT ON ...
үчүн комментарийлер всех объектилер, кошпостон.
Жергиликтүү аудит
Сакталган функциялардын аткарылышын жана максаттуу таблицаларга өзгөртүүлөрдү киргизүү үчүн локалдык аудит таблицасы колдонулат, ал башка нерселер менен катар кардар байланышынын деталдарын, чакырылган модулдун этикеткасын жана киргизүүнүн чыныгы маанилерин жана чыгаруу параметрлери JSON түрүндө.
Системалык функциялар
Максаттуу таблицалардагы өзгөртүүлөрдү киргизүү үчүн иштелип чыккан. Алар триггер функциялары.
Шаблон - системанын функциясы
---------------------------------------------------------
-- INSERT
CREATE OR REPLACE FUNCTION sys_functions.table_insert_log ()
RETURNS TRIGGER AS $$
BEGIN
PERFORM loc_audit_functions.make_log( ' '||'table' , 'insert' , json_build_object('id', NEW.id) );
RETURN NULL ;
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
CREATE TRIGGER table_after_insert AFTER INSERT ON storage.table FOR EACH ROW EXECUTE PROCEDURE sys_functions.table_insert_log();
---------------------------------------------------------
-- UPDATE
CREATE OR REPLACE FUNCTION sys_functions.table_update_log ()
RETURNS TRIGGER AS $$
BEGIN
IF OLD.column != NEW.column
THEN
PERFORM loc_audit_functions.make_log( ' '||'table' , 'update' , json_build_object('OLD.column', OLD.column , 'NEW.column' , NEW.column ) );
END IF ;
RETURN NULL ;
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
CREATE TRIGGER table_after_update AFTER UPDATE ON storage.table FOR EACH ROW EXECUTE PROCEDURE sys_functions.table_update_log ();
---------------------------------------------------------
-- DELETE
CREATE OR REPLACE FUNCTION sys_functions.table_delete_log ()
RETURNS TRIGGER AS $$
BEGIN
PERFORM loc_audit_functions.make_log( ' '||'table' , 'delete' , json_build_object('id', OLD.id ) );
RETURN NULL ;
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
CREATE TRIGGER table_after_delete AFTER DELETE ON storage.table FOR EACH ROW EXECUTE PROCEDURE sys_functions.table_delete_log ();
Тейлөө функциялары
Максаттуу таблицаларда тейлөө жана DML операцияларын ишке ашыруу үчүн иштелип чыккан.
Үлгү - тейлөө функциясы
--INSERT
--RETURN id OF NEW ROW
CREATE OR REPLACE FUNCTION service_functions.table_insert ( new_column store.table.column%TYPE )
RETURNS integer AS $$
DECLARE
new_id integer ;
BEGIN
-- Generate new id
new_id = nextval('store.table.seq');
-- Insert into table
INSERT INTO store.table
(
id ,
column
)
VALUES
(
new_id ,
new_column
);
RETURN new_id ;
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
--DELETE
--RETURN ROW NUMBERS DELETED
CREATE OR REPLACE FUNCTION service_functions.table_delete ( current_id integer )
RETURNS integer AS $$
DECLARE
rows_count integer ;
BEGIN
DELETE FROM store.table WHERE id = current_id;
GET DIAGNOSTICS rows_count = ROW_COUNT;
RETURN rows_count ;
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- UPDATE DETAILS
-- RETURN ROW NUMBERS UPDATED
CREATE OR REPLACE FUNCTION service_functions.table_update_column
(
current_id integer
,new_column store.table.column%TYPE
)
RETURNS integer AS $$
DECLARE
rows_count integer ;
BEGIN
UPDATE store.table
SET
column = new_column
WHERE id = current_id;
GET DIAGNOSTICS rows_count = ROW_COUNT;
RETURN rows_count ;
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
Бизнес функциялары
Кардар чакырган акыркы бизнес функциялары үчүн иштелип чыккан. Алар ар дайым кайтып келет - JSON. Аткаруу каталарын кармоо жана журналга коюу үчүн блокту колдонуңуз ЧЫГАРУУ.
Шаблон - бизнес функциясы
CREATE OR REPLACE FUNCTION business_functions.business_function_template(
--Input parameters
)
RETURNS JSON AS $$
DECLARE
------------------------
--for exception catching
error_message text ;
error_json json ;
result json ;
------------------------
BEGIN
--LOGGING
PERFORM loc_audit_functions.make_log
(
'business_function_template',
'STARTED',
json_build_object
(
--IN Parameters
)
);
PERFORM business_functions.notice('business_function_template');
--START BUSINESS PART
--END BUSINESS PART
-- SUCCESFULLY RESULT
PERFORM business_functions.notice('result');
PERFORM business_functions.notice(result);
PERFORM loc_audit_functions.make_log
(
'business_function_template',
'FINISHED',
json_build_object( 'result',result )
);
RETURN result ;
----------------------------------------------------------------------------------------------------------
-- EXCEPTION CATCHING
EXCEPTION
WHEN OTHERS THEN
PERFORM loc_audit_functions.make_log
(
'business_function_template',
'STARTED',
json_build_object
(
--IN Parameters
) , TRUE );
PERFORM loc_audit_functions.make_log
(
'business_function_template',
' ERROR',
json_build_object('SQLSTATE',SQLSTATE ), TRUE
);
PERFORM loc_audit_functions.make_log
(
'business_function_template',
' ERROR',
json_build_object('SQLERRM',SQLERRM ), TRUE
);
GET STACKED DIAGNOSTICS error_message = RETURNED_SQLSTATE ;
PERFORM loc_audit_functions.make_log
(
'business_function_template',
' ERROR-RETURNED_SQLSTATE',json_build_object('RETURNED_SQLSTATE',error_message ), TRUE );
GET STACKED DIAGNOSTICS error_message = COLUMN_NAME ;
PERFORM loc_audit_functions.make_log
(
'business_function_template',
' ERROR-COLUMN_NAME',
json_build_object('COLUMN_NAME',error_message ), TRUE );
GET STACKED DIAGNOSTICS error_message = CONSTRAINT_NAME ;
PERFORM loc_audit_functions.make_log
(
'business_function_template',
' ERROR-CONSTRAINT_NAME',
json_build_object('CONSTRAINT_NAME',error_message ), TRUE );
GET STACKED DIAGNOSTICS error_message = PG_DATATYPE_NAME ;
PERFORM loc_audit_functions.make_log
(
'business_function_template',
' ERROR-PG_DATATYPE_NAME',
json_build_object('PG_DATATYPE_NAME',error_message ), TRUE );
GET STACKED DIAGNOSTICS error_message = MESSAGE_TEXT ;
PERFORM loc_audit_functions.make_log
(
'business_function_template',
' ERROR-MESSAGE_TEXT',json_build_object('MESSAGE_TEXT',error_message ), TRUE );
GET STACKED DIAGNOSTICS error_message = SCHEMA_NAME ;
PERFORM loc_audit_functions.make_log
(s
'business_function_template',
' ERROR-SCHEMA_NAME',json_build_object('SCHEMA_NAME',error_message ), TRUE );
GET STACKED DIAGNOSTICS error_message = PG_EXCEPTION_DETAIL ;
PERFORM loc_audit_functions.make_log
(
'business_function_template',
' ERROR-PG_EXCEPTION_DETAIL',
json_build_object('PG_EXCEPTION_DETAIL',error_message ), TRUE );
GET STACKED DIAGNOSTICS error_message = PG_EXCEPTION_HINT ;
PERFORM loc_audit_functions.make_log
(
'business_function_template',
' ERROR-PG_EXCEPTION_HINT',json_build_object('PG_EXCEPTION_HINT',error_message ), TRUE );
GET STACKED DIAGNOSTICS error_message = PG_EXCEPTION_CONTEXT ;
PERFORM loc_audit_functions.make_log
(
'business_function_template',
' ERROR-PG_EXCEPTION_CONTEXT',json_build_object('PG_EXCEPTION_CONTEXT',error_message ), TRUE );
RAISE WARNING 'ALARM: %' , SQLERRM ;
SELECT json_build_object
(
'isError' , TRUE ,
'errorMsg' , SQLERRM
) INTO error_json ;
RETURN error_json ;
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
жыйынтык
Жалпы сүрөттү сүрөттөө үчүн, мен бул жетиштүү деп ойлойм. Эгерде кимдир-бирөөнүн чоо-жайы жана натыйжалары кызыкса, комментарий жазыңыз, мен сүрөткө кошумча түстөрдү кошууга кубанычта болом.
PS
Жөнөкөй ката журналы - киргизүү параметр түрү
-[ RECORD 1 ]- date_trunc | 2020-08-19 13:15:46 id | 1072 usename | emp1 log_module | addKD log_module_hash | 0b4c1529a89af3ddf6af3821dc790e8a status | STARTED jsonb_pretty | { | "dko": { | "id": 4, | "type": "Type1", | "title": "CREATED BY addKD", | "Weight": 10, | "Tr": "300", | "reduction": 10, | "isTrud": "TRUE", | "description": "decription", | "lowerTr": "100", | "measurement": "measurement1", | "methodology": "m1", | "passportUrl": "files", | "upperTr": "200", | "weightingFactor": 100.123, | "actualTrValue": null, | "upperTrCalcNumber": "120" | }, | "CardId": 3 | } -[ RECORD 2 ]- date_trunc | 2020-08-19 13:15:46 id | 1073 usename | emp1 log_module | addKD log_module_hash | 0b4c1529a89af3ddf6af3821dc790e8a status | ERROR jsonb_pretty | { | "SQLSTATE": "22P02" | } -[ RECORD 3 ]- date_trunc | 2020-08-19 13:15:46 id | 1074 usename | emp1 log_module | addKD log_module_hash | 0b4c1529a89af3ddf6af3821dc790e8a status | ERROR jsonb_pretty | { | "SQLERRM": "invalid input syntax for type numeric: "null"" | } -[ RECORD 4 ]- date_trunc | 2020-08-19 13:15:46 id | 1075 usename | emp1 log_module | addKD log_module_hash | 0b4c1529a89af3ddf6af3821dc790e8a status | ERROR-RETURNED_SQLSTATE jsonb_pretty | { | "RETURNED_SQLSTATE": "22P02" | } -[ RECORD 5 ]- date_trunc | 2020-08-19 13:15:46 id | 1076 usename | emp1 log_module | addKD log_module_hash | 0b4c1529a89af3ddf6af3821dc790e8a status | ERROR-COLUMN_NAME jsonb_pretty | { | "COLUMN_NAME": "" | } -[ RECORD 6 ]- date_trunc | 2020-08-19 13:15:46 id | 1077 usename | emp1 log_module | addKD log_module_hash | 0b4c1529a89af3ddf6af3821dc790e8a status | ERROR-CONSTRAINT_NAME jsonb_pretty | { | "CONSTRAINT_NAME": "" | } -[ RECORD 7 ]- date_trunc | 2020-08-19 13:15:46 id | 1078 usename | emp1 log_module | addKD log_module_hash | 0b4c1529a89af3ddf6af3821dc790e8a status | ERROR-PG_DATATYPE_NAME jsonb_pretty | { | "PG_DATATYPE_NAME": "" | } -[ RECORD 8 ]- date_trunc | 2020-08-19 13:15:46 id | 1079 usename | emp1 log_module | addKD log_module_hash | 0b4c1529a89af3ddf6af3821dc790e8a status | ERROR-MESSAGE_TEXT jsonb_pretty | { | "MESSAGE_TEXT": "invalid input syntax for type numeric: "null"" | } -[ RECORD 9 ]- date_trunc | 2020-08-19 13:15:46 id | 1080 usename | emp1 log_module | addKD log_module_hash | 0b4c1529a89af3ddf6af3821dc790e8a status | ERROR-SCHEMA_NAME jsonb_pretty | { | "SCHEMA_NAME": "" | } -[ RECORD 10 ]- date_trunc | 2020-08-19 13:15:46 id | 1081 usename | emp1 log_module | addKD log_module_hash | 0b4c1529a89af3ddf6af3821dc790e8a status | ERROR-PG_EXCEPTION_DETAIL jsonb_pretty | { | "PG_EXCEPTION_DETAIL": "" | } -[ RECORD 11 ]- date_trunc | 2020-08-19 13:15:46 id | 1082 usename | emp1 log_module | addKD log_module_hash | 0b4c1529a89af3ddf6af3821dc790e8a status | ERROR-PG_EXCEPTION_HINT jsonb_pretty | { | "PG_EXCEPTION_HINT": "" | } -[ RECORD 12 ]- date_trunc | 2020-08-19 13:15:46 id | 1083 usename | emp1 log_module | addKD log_module_hash | 0b4c1529a89af3ddf6af3821dc790e8a status | ERROR-PG_EXCEPTION_CONTEXT jsonb_pretty | { usename | emp1 log_module | addKD log_module_hash | 0b4c1529a89af3ddf6af3821dc790e8a status | ERROR-MESSAGE_TEXT jsonb_pretty | { | "MESSAGE_TEXT": "invalid input syntax for type numeric: "null"" | }
Source: www.habr.com