锘??xml version="1.0" encoding="utf-8" standalone="yes"?> The object of an effective coding style is to make the program more understandable and maintainable. Most programs will benefit from documentation which explains what is going on inside those programs. There are two forms of code documentation: external and internal. External documentation is descriptive information about a program which is written and stored separately from the program itself. Internal documentation, also known as inline documentation or comments, is placed within the program itself, either at the program level or the statement level. (For an introduction to inline documentation and the types of PL/SQL comments, see the section called "Comments" in Chapter 2.)
The best kind of internal documentation derives from your programming style. If you apply many of the guidelines in this chapter and throughout this book, you will be able to write code which is, to a great extent, self-documenting. Here are some general tips:
Do all these things and more, and you will find that you need to write fewer comments to explain your code.
Reducing the need for comments is important. Few developers make or have the time for extensive documentation in addition to their development efforts, and, more importantly, many comments tend to duplicate the code. This raises a maintenance issue because those comments will have to be changed when the code is changed.
While it is my hope that after reading this book you will write more self-documenting code, there is little doubt that you will still need to comment your code. The following example shows the use of single- and multiline comments in PL/SQL:
The first example uses the single-line comment syntax to include endline descriptions for each parameter in the procedure specification. The second example uses a multiline comment to explain the purpose of the FOR loop. The third example uses the double-hyphen to comment out a whole line of code. The last example embeds a comment in the middle of a line of code using the block comment syntax.
These two types of comments offer the developer flexibility in how to provide inline documentation. The rest of this section offers guidelines for writing effective comments in your PL/SQL programs.
It is very difficult to make time to document your code after you have finished writing your program. Psychologically, you want to (and often need to) move on to the next programming challenge after you get a program working.
You may also have a harder time writing your comments once you have put some distance between your brain cells and those lines of code. Why exactly did you write the loop that way? Where precisely is the value of that global variable set? Unless you have total recall, post-development documentation can be a real challenge.
The last and perhaps most important reason to write your comments as you write your code is that the resulting code will have fewer bugs and (independent of the comments themselves) be easier to understand.
When you write a comment you (theoretically) explain what your code is meant to accomplish. If you find it difficult to come up with that explanation, there is a good chance that you lack a full understanding of what the program does or should do.
The effort that you make to come up with the right comment will certainly improve your comprehension, and may also result in code correction. In this sense, good inline documentation can be as beneficial as a review of your code by a peer. In both cases, the explanation will reveal important information about your program.
What do you think of the comments in the following Oracle Forms trigger code?
None of these comments add anything to the comprehension of the code. Each comment simply restates the line of code, which in most cases is self-explanatory.
Avoid adding comments simply so that you can say, "Yes, I documented my code!" Rely as much as possible on the structure and layout of the code itself to express the meaning of the program. Reserve your comments to explain the Why of your code: What business rule is it meant to implement? Why did you need to implement a certain requirement in a certain way?
In addition, use comments to translate internal, computer-language terminology into something meaningful for the application. Suppose you are using Oracle Forms GLOBAL variables to keep track of a list of names entered. Does the following comment explain the purpose of the code or simply restate what the code is doing?
Once again, the comment adds no value. Does the next comment offer additional information?
This comment actually explains the purpose of the assignment of the global to zero. By setting the number of elements to zero, I will have effectively emptied the list. This comment has translated the "computer lingo" into a description of the effect of the statement. Of course, you would be even better off hiding the fact that you use this particular global variable to empty a list and instead build a procedure as follows:
PROCEDURE empty_list IS
BEGIN
:GLOBAL.num_elements := 0;
Then to empty a list you would not need any comment at all. You could simply include the statement:
and the meaning would be perfectly clear.
You shouldn't spend a lot of time formatting your comments. You need to develop a style that is clean and easy to read, but also easy to maintain. When you have to change a comment, you shouldn't have to reformat every line in the comment. Lots of fancy formatting is a good indication that you have a high-maintenance documentation style. The following block comment is a maintenance nightmare:
The right-justified vertical lines and column formatting for the parameters require way too much effort to enter and maintain. What happens if you add a parameter with a very long name? What if you need to write a longer description? A simpler and more maintainable version of this comment might be:
I like to use the following format for my block comments:
|| vertical bar to highlight the presence of the comment. Finally,
|| I place the asterisk-slash on a line all by itself.
On the negative side, the vertical bars have to be erased whenever I reformat the lines, but that isn't too much of an effort. On the positive side, those vertical bars make it very easy for a programmer who is scanning the left side of the code to pick out the comments.
I put the comment markers on their own lines to increase the whitespace in my program and set off the comment. That way I can avoid "heavy" horizontal lines full of delimiters, such as asterisks or dashes, and avoid having to match the longest line in the comment.
Inline commentary should reinforce the indentation and therefore the logical structure of the program. For example, it is very easy to find the comments in the make_array procedures shown below. I do not use any double-hyphens, so the slash-asterisk sequences stand out nicely. In addition, all comments start in the first column, so I can easily scan down the left-hand side of the program and pick out the documentation:
END LOOP;
The problem with these comments is precisely that they do all start in the first column, regardless of the code they describe. The most glaring example of this formatting "disconnect" comes in the inner loop, repeated below:
Your eye follows the three-space indentation very smoothly into the loop and then you are forced to move all the way to the left to pick up the comment. This format disrupts your reading of the code and therefore its readability. The code loses some of its ability to communicate the logical flow "at a glance," because the physical sense of indentation as logical flow is marred by the comments. Finally, you may end up writing full-line comments which are much longer than the code they appear next to, further distorting the code.
Your comments should always be indented at the same level as the code which they describe. Assuming the comments come before the code itself, those lines of descriptive text will initiate the indentation at that logical level, which will also reinforce that structure. The make_array procedure, properly indented, is shown below:
END LOOP;
END LOOP;
I propose the following simple rule for documenting declaration statements:
Does that sound excessive? Well, I must admit that I do not follow this guideline at all times, but I bet people who read my code wish I had. The declaration of a variable which seems to me to be perfectly clear may be a source of abiding confusion for others. Like many other people, I still have difficulty understanding that what is obvious to me is not necessarily obvious to someone else. Consider the declaration section in the next example. The commenting style is inconsistent. I use double-hyphens for a two-line comment; then I use the standard block format to provide information about three variables all at once. I provide comments for some variables, but not for others. It's hard to make sense of the various declaration statements: Let's recast this declaration section using my proposed guideline: a comment for each declaration statement. In the result shown below, the declaration section is now longer than the first version, but it uses whitespace more effectively. Each declaration has its own comment, set off by a blank line if a single-line comment:
PROCEDURE calc_totals (company_id IN NUMBER,--The company key
total_type IN VARCHAR2--ALL or NET
);
/*
|| For every employee hired more than five years ago,
|| give them a bonus and send them an e-mail notification.
*/
FOR emp_rec IN emp_cur (ADD_MONTHS (SYSDATE, -60))
LOOP
apply_bonus (emp_rec.employee_id);
send_notification (emp_rec.employee_id);
END LOOP;
-- IF :SYSTEM.FORM_STATUS = 'CHANGED' THEN COMMIT; END IF;
FUNCTION display_user
(user_id IN NUMBER /* Must be valid ID */, user_type IN VARCHAR2)
Comment As You Code
Explain the Why--Not the How--of Your Program
-- If the total compensation is more than the maximum...
IF :employee.total_comp > maximum_salary
THEN
-- Inform the user of the problem.
MESSAGE ('Total compensation exceeds maximum. Please re-enter!');
-- Reset the counter to zero.
:employee.comp_counter := 0;
-- Raise the exception to stop trigger processing.
RAISE FORM_TRIGGER_FAILURE;
END IF;
/* Set the number of elements to zero. */
:GLOBAL.num_elements := 0;
/* Empty the list of names. */
:GLOBAL.num_elements := 0;
END;
empty_list;
Make Comments Easy to Enter and Maintain
/*
===========================================================
| Parameter Description |
| |
| company_id The primary key to company |
| start_date Start date used for date range |
| end_date End date for date range |
===========================================================
*/
/*
===========================================================
| Parameter - Description
|
| company_id - The primary key to company
| start_date - Start date used for date range
| end_date - End date for date range
===========================================================
*/
/*
|| I put the slash-asterisk that starts the comment on a line all by
|| itself. Then I start each line in the comment block with a double
*/
Maintain Indentation
PROCEDURE make_array (num_rows_in IN INTEGER)
/* Create an array of specified numbers of rows */
IS
/* Handles to Oracle Forms structures */
col_id GROUPCOLUMN;
rg_id RECORDGROUP;
BEGIN
/* Create new record group and column */
rg_id := CREATE_GROUP ('array');
col_id := ADD_GROUP_COLUMN ('col');
/*
|| Use a loop to create the specified number of rows and
|| set the value in each cell.
*/
FOR row_index IN 1 .. num_rows_in
LOOP
/* Create a row at the end of the group to accept data */
ADD_GROUP_ROW (return_value, END_OF_GROUP);
FOR col_index IN 1 .. num_columns_in
LOOP
/* Set the initial value in the cell */
SET_GROUP_NUMBER_CELL (col_id, row_index, 0);
END LOOP;
END;
FOR col_index IN 1 .. num_columns_in
LOOP
/* Set the initial value in the cell */
SET_GROUP_NUMBER_CELL (col_id, row_index, 0);
END LOOP;
PROCEDURE make_array (num_rows_in IN INTEGER)
/* Create an array of specified numbers of rows */
IS
/* Handles to Oracle Forms structures */
col_id GROUPCOLUMN;
rg_id RECORDGROUP;
BEGIN
/* Create new record group and column */
rg_id := CREATE_GROUP ('array');
col_id := ADD_GROUP_COLUMN ('col');
/*
|| Use a loop to create the specified number of rows and
|| set the value in each cell.
*/
FOR row_index IN 1 .. num_rows_in
LOOP
/* Create a row at the end of the group to accept data */
ADD_GROUP_ROW (return_value, END_OF_GROUP);
FOR col_index IN 1 .. num_columns_in
LOOP
/* Set the initial value in the cell */
SET_GROUP_NUMBER_CELL (col_id, row_index, 0);
END;
Comment Declaration Statements
Provide a comment for each and every declaration.
DECLARE
-- Assume a maximum string length of 1000 for a line of text.
text_line VARCHAR2 (1000);
len_text NUMBER;
/*
|| Variables used to keep track of string scan:
|| atomic_count - running count of atomics scanned.
|| still_scanning - Boolean variable controls WHILE loop.
*/
atomic_count NUMBER := 1;
still_scanning BOOLEAN;
BEGIN
DECLARE
/* Assume a maximum string length of 1000 for a line of text. */
text_line VARCHAR2 (1000);
/* Calculate length of string at time of declaration */
len_string NUMBER;
/* Running count of number of atomics scanned */
atomic_count NUMBER := 1;
/* Boolean variable that controls WHILE loop */
still_scanning BOOLEAN ;
BEGIN
]]>
table level triggers: 鏄痶able鏀瑰彉鏃訛紝瑙﹀彂trigger銆傛棤璁哄嚑涓猺ow鏀瑰彉閮芥病褰卞搷, 姣斿錛?涓猺ow update瑙﹀彂1嬈?,錛掍釜row update錛屼篃瑙﹀彂1嬈°?br />
欏轟究杞釜鏁欑▼
Before / for each row trigger
:new.field_name
) are stored in the table. That means that the new value can be changed in the trigger. create table t_update_before_each_row (
txt varchar2(10)
);
create table log (
txt varchar2(20)
);
create trigger update_before_each_row
before update on t_update_before_each_row
for each row
begin
:new.txt := upper(:new.txt);
insert into log values ('old: ' || :old.txt);
insert into log values ('new: ' || :new.txt);
end update_before_each_row;
/
insert into t_update_before_each_row values('one');
insert into t_update_before_each_row values('two');
insert into t_update_before_each_row values('three');
insert into t_update_before_each_row values('four');
update t_update_before_each_row set txt = txt || txt
where substr(txt,1,1) = 't';
select * from t_update_before_each_row;
one
TWOTWO
THREETHREE
four
select * from log;
old: two
new: TWOTWO
old: three
new: THREETHREE
drop table t_update_before_each_row;
drop table log;
After / for each row trigger
:new.field_name
because the value is, when the trigger fires, already written to the table. :new.field_name
, Oracle throws an ORA-04084: cannot change NEW values for this trigger type. create table t_update_after_each_row (
txt varchar2(10)
);
create table log (
txt varchar2(20)
);
create trigger update_after_each_row
after update on t_update_after_each_row
for each row
begin
-- :new.txt := upper(:old.txt); -- ORA-04084: cannot change NEW values for this trigger type
insert into log values ('old: ' || :old.txt);
insert into log values ('new: ' || :new.txt);
end update_after_each_row;
/
insert into t_update_after_each_row values('one');
insert into t_update_after_each_row values('two');
insert into t_update_after_each_row values('three');
insert into t_update_after_each_row values('four');
update t_update_after_each_row set txt = txt || txt
where substr(txt,1,1) = 't';
select * from t_update_after_each_row;
one
twotwo
threethree
four
select * from log;
:new
and :old
although it's not possible to assign something to :new
. old: two
new: twotwo
old: three
new: threethree
drop table t_update_after_each_row;
drop table log;
Table level trigger
for each row
. Consequently, both, the :new
and :old
are not permitted in the trigger's PL/SQL block, otherwise, an ORA-04082: NEW or OLD references not allowed in table level triggers is thrown. create table t_update_before (
txt varchar2(10)
);
create table log (
txt varchar2(20)
);
create trigger update_before
before update on t_update_before
begin
-- :new.txt := upper(:old.txt); -- ORA-04082
insert into log values ('update trigger');
end update_before;
/
insert into t_update_before values('one');
insert into t_update_before values('two');
insert into t_update_before values('three');
insert into t_update_before values('four');
update t_update_before set txt = txt || txt
where substr(txt,1,1) = 't';
select * from t_update_before;
one
twotwo
threethree
four
select * from log;
update trigger
update t_update_before set txt = txt || txt
where txt = 'no update';
select * from log;
update trigger
update trigger
drop table t_update_before;
drop table log;
Order of execution
]]>
姝g‘鏍煎紡涓?
鍙互鐢ㄤ袱縐嶆柟寮忓垱寤?span>MySQL璐︽埛錛?/p>
· 浣跨敤GRANT璇彞
· 鐩存帴鎿嶄綔MySQL鎺堟潈琛?/p>
鏈濂界殑鏂規(guī)硶鏄嬌鐢?span>GRANT璇彞錛屽洜涓鴻繖鏍鋒洿綺劇‘錛岄敊璇皯銆備粠MySQL 3.22.11璧鋒彁渚涗簡(jiǎn)GRANT錛涘叾璇硶瑙?a title="13.5.1.3. GRANT and REVOKE Syntax" >13.5.1.3鑺傦紝“GRANT鍜孯EVOKE璇硶”銆?/p>
鍒涘緩璐︽埛鐨勫叾瀹冩柟娉曟槸浣跨敤MySQL璐︽埛綆$悊鍔熻兘鐨勭涓夋柟紼嬪簭銆?span>phpMyAdmin鍗蟲槸涓涓▼搴忋?/p>
涓嬮潰鐨勭ず渚嬭鏄庡浣曚嬌鐢?strong>MySQL瀹㈡埛绔▼搴忔潵璁劇疆鏂扮敤鎴楓傚亣瀹氭寜鐓?a title="2.9.3. Securing the Initial MySQL Accounts" >2.9.3鑺傦紝“浣垮垵濮婱ySQL璐︽埛瀹夊叏”鎻忚堪鐨?榛樿鍊兼潵璁劇疆鏉冮檺銆傝繖璇存槑涓轟簡(jiǎn)鏇存敼錛屼綘蹇呴』浠?span>MySQL root鐢ㄦ埛榪炴帴MySQL鏈嶅姟鍣紝騫朵笖root璐︽埛蹇呴』鏈?span>mysql鏁版嵁搴撶殑INSERT鏉冮檺鍜?span>RELOAD綆$悊鏉冮檺銆?/p>
棣栧厛錛屼嬌鐢?strong>MySQL紼嬪簭浠?span>MySQL root鐢ㄦ埛鏉ヨ繛鎺ユ湇鍔″櫒錛?/p>
shell> MySQL --user=root MySQL
濡傛灉浣犱負(fù)root璐︽埛鎸囧畾浜?jiǎn)瀵嗙爜锛寴q橀渶瑕佷負(fù)璇?strong>MySQL鍛戒護(hù)鍜屾湰鑺備腑鐨勫叾瀹冨懡浠ゆ彁渚?span>--password鎴?span>-p閫夐」銆?/p>
浠?span>root榪炴帴鍒版湇鍔″櫒涓婂悗錛屽彲浠ユ坊鍔犳柊璐︽埛銆備笅闈㈢殑璇彞浣跨敤GRANT鏉ヨ緗洓涓柊璐︽埛錛?/p>
mysql> GRANT ALL PRIVILEGES ON *.* TO 'monty'@'localhost'
-> IDENTIFIED BY 'some_pass' WITH GRANT OPTION;
mysql> GRANT ALL PRIVILEGES ON *.* TO 'monty'@'%'
-> IDENTIFIED BY 'some_pass' WITH GRANT OPTION;
mysql> GRANT RELOAD,PROCESS ON *.* TO 'admin'@'localhost';
mysql> GRANT USAGE ON *.* TO 'dummy'@'localhost';
鐢?span>GRANT璇彞鍒涘緩鐨勮處鎴鋒湁涓嬮潰鐨勫睘鎬э細(xì)
· 鍏朵腑涓や釜璐︽埛鏈夌浉鍚岀殑鐢ㄦ埛鍚?span>monty鍜屽瘑鐮?span>some_pass銆備袱涓處鎴峰潎涓鴻秴綰х敤鎴瘋處鎴鳳紝鍏鋒湁瀹屽叏鐨勬潈闄愬彲浠ュ仛浠諱綍浜嬫儏銆備竴涓處鎴?span> ('monty'@'localhost')鍙敤浜庝粠鏈満榪炴帴鏃躲傚彟涓涓處鎴?span>('monty'@'%')鍙敤浜庝粠鍏跺畠涓繪満榪炴帴銆傝娉ㄦ剰monty鐨勪袱涓處鎴峰繀欏昏兘浠庝換浣曚富鏈轟互monty榪炴帴銆傛病鏈?span>localhost璐︽埛錛屽綋monty浠庢湰鏈鴻繛鎺ユ椂錛?strong>mysql_install_db鍒涘緩鐨?span>localhost鐨勫尶鍚嶇敤鎴瘋處鎴峰皢鍗犲厛銆傜粨鏋滄槸錛?span>monty灝嗚瑙嗕負(fù)鍖垮悕鐢ㄦ埛銆傚師鍥犳槸鍖垮悕鐢ㄦ埛璐︽埛鐨?span>Host鍒楀兼瘮'monty'@'%'璐︽埛鏇村叿浣擄紝榪欐牱鍦?span>user琛ㄦ帓搴忛『搴忎腑鎺掑湪鍓嶉潰銆?span>(user琛ㄦ帓搴忕殑璁ㄨ鍙傝5.7.5鑺傦紝“璁塊棶鎺у埗, 闃舵1錛氳繛鎺ユ牳瀹?#8221;錛?span>銆?
· 涓涓處鎴鋒湁鐢ㄦ埛鍚?span>admin錛屾病鏈夊瘑鐮併傝璐︽埛鍙敤浜庝粠鏈満榪炴帴銆傛巿浜堜簡(jiǎn)RELOAD鍜?span>PROCESS綆$悊鏉冮檺銆傝繖浜涙潈闄愬厑璁?span>admin鐢ㄦ埛鎵цmysqladmin reload銆?strong>mysqladmin refresh鍜?strong>mysqladmin flush-xxx鍛戒護(hù)錛屼互鍙?strong>mysqladmin processlist銆傛湭鎺堜簣璁塊棶鏁版嵁搴撶殑鏉冮檺銆備綘鍙互閫氳繃GRANT璇彞娣誨姞姝ょ被鏉冮檺銆?/p>
· 涓涓處鎴鋒湁鐢ㄦ埛鍚?span>dummy錛屾病鏈夊瘑鐮併傝璐︽埛鍙敤浜庝粠鏈満榪炴帴銆傛湭鎺堜簣鏉冮檺銆傞氳繃GRANT璇彞涓殑USAGE鏉冮檺錛屼綘鍙互鍒涘緩璐︽埛鑰屼笉鎺堜簣浠諱綍鏉冮檺銆傚畠鍙互灝嗘墍鏈夊叏灞鏉冮檺璁句負(fù)'N'銆傚亣瀹氫綘灝嗗湪浠ュ悗灝嗗叿浣撴潈闄愭巿浜堣璐︽埛銆?/p>
闄や簡(jiǎn)GRANT錛屼綘鍙互鐩存帴鐢?span>INSERT璇彞鍒涘緩鐩稿悓鐨勮處鎴鳳紝鐒跺悗浣跨敤FLUSH PRIVILEGES鍛婅瘔鏈嶅姟鍣ㄩ噸杞芥巿鏉冭〃錛?/p>
shell> mysql --user=root mysql
mysql> INSERT INTO user
-> VALUES('localhost','monty',PASSWORD('some_pass'),
-> 'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
mysql> INSERT INTO user
-> VALUES('%','monty',PASSWORD('some_pass'),
-> 'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
mysql> INSERT INTO user SET Host='localhost',User='admin',
-> Reload_priv='Y', Process_priv='Y';
mysql> INSERT INTO user (Host,User,Password)
-> VALUES('localhost','dummy','');
mysql> FLUSH PRIVILEGES;
褰撲綘鐢?span>INSERT鍒涘緩璐︽埛鏃朵嬌鐢?span>FLUSH PRIVILEGES鐨勫師鍥犳槸鍛婅瘔鏈嶅姟鍣ㄩ噸璇繪巿鏉冭〃銆傚惁鍒欙紝鍙湁閲嶅惎鏈嶅姟鍣ㄥ悗鏇存敼鏂逛細(xì)琚敞鎰忓埌銆備嬌鐢?GRANT錛屽垯涓嶉渶瑕佷嬌鐢?span>FLUSH PRIVILEGES銆?/p>
鐢?span>INSERT浣跨敤PASSWORD()鍑芥暟鏄負(fù)浜?jiǎn)鍔犲瘑瀵嗙爜銆?span>GRANT璇彞涓轟綘鍔犲瘑瀵嗙爜錛屽洜姝や笉闇瑕?span>PASSWORD()銆?/p>
'Y'鍊煎惎鐢ㄨ處鎴鋒潈闄愩傚浜?span>admin璐︽埛錛岃繕鍙互浣跨敤鏇村姞鍙鐨?span>INSERT鎵╁厖鐨勮娉曪紙浣跨敤SET錛夈?/p>
鍦ㄤ負(fù)dummy璐︽埛鐨?span>INSERT璇彞涓紝鍙湁user琛ㄤ腑鐨?span>Host銆?span>User鍜?span>Password鍒楄褰曚負(fù)鎸囧畾鐨勫箋傛病鏈変竴涓潈闄愬垪涓烘樉寮忚緗紝鍥犳MySQL灝嗗畠浠潎鎸囧畾涓?榛樿鍊?span>'N'銆傝繖鏍風(fēng)瓑鍚屼簬GRANT USAGE鐨勬搷浣溿?/p>
璇鋒敞鎰忚璁劇疆瓚呯駭鐢ㄦ埛璐︽埛錛屽彧闇瑕佸垱寤轟竴涓潈闄愬垪璁劇疆涓?span>'Y'鐨?span>user琛ㄦ潯鐩?span>user琛ㄦ潈闄愪負(fù)鍏ㄥ眬鏉冮檺錛屽洜姝ゅ叾瀹?鎺堟潈琛ㄤ笉鍐嶉渶瑕佹潯鐩?/p>
涓嬮潰鐨勪緥瀛愬垱寤?span>3涓處鎴鳳紝鍏佽瀹冧滑璁塊棶涓撶敤鏁版嵁搴撱傛瘡涓處鎴風(fēng)殑鐢ㄦ埛鍚嶄負(fù)custom錛屽瘑鐮佷負(fù)obscure銆?/span>
瑕佹兂鐢?span>GRANT鍒涘緩璐︽埛錛屼嬌鐢ㄤ笅闈㈢殑璇彞錛?/p>
shell> MySQL --user=root MySQL
shell> mysql --user=root mysql
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
-> ON bankaccount.*
-> TO 'custom'@'localhost'
-> IDENTIFIED BY 'obscure';
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
-> ON expenses.*
-> TO 'custom'@'whitehouse.gov'
-> IDENTIFIED BY 'obscure';
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
-> ON customer.*
-> TO 'custom'@'server.domain'
-> IDENTIFIED BY 'obscure';
榪?span>3涓處鎴峰彲浠ョ敤浜庯細(xì)
· 絎?span>1涓處鎴峰彲浠ヨ闂?span>bankaccount鏁版嵁搴擄紝浣嗗彧鑳戒粠鏈満璁塊棶銆?/p>
· 絎?span>2涓處鎴峰彲浠ヨ闂?span>expenses鏁版嵁搴擄紝浣嗗彧鑳戒粠涓繪満whitehouse.gov璁塊棶銆?/p>
· 絎?span>3涓處鎴峰彲浠ヨ闂?span>customer鏁版嵁搴擄紝浣嗗彧鑳戒粠涓繪満server.domain璁塊棶銆?/p>
瑕佹兂涓嶇敤GRANT璁劇疆custom璐︽埛錛屼嬌鐢?span>INSERT璇彞鐩存帴淇敼 鎺堟潈琛細(xì)
shell> mysql --user=root mysql
mysql> INSERT INTO user (Host,User,Password)
-> VALUES('localhost','custom',PASSWORD('obscure'));
mysql> INSERT INTO user (Host,User,Password)
-> VALUES('whitehouse.gov','custom',PASSWORD('obscure'));
mysql> INSERT INTO user (Host,User,Password)
-> VALUES('server.domain','custom',PASSWORD('obscure'));
mysql> INSERT INTO db
-> (Host,Db,User,Select_priv,Insert_priv,
-> Update_priv,Delete_priv,Create_priv,Drop_priv)
-> VALUES('localhost','bankaccount','custom',
-> 'Y','Y','Y','Y','Y','Y');
mysql> INSERT INTO db
-> (Host,Db,User,Select_priv,Insert_priv,
-> Update_priv,Delete_priv,Create_priv,Drop_priv)
-> VALUES('whitehouse.gov','expenses','custom',
-> 'Y','Y','Y','Y','Y','Y');
mysql> INSERT INTO db
-> (Host,Db,User,Select_priv,Insert_priv,
-> Update_priv,Delete_priv,Create_priv,Drop_priv)
-> VALUES('server.domain','customer','custom',
-> 'Y','Y','Y','Y','Y','Y');
mysql> FLUSH PRIVILEGES;
鍓?span>3涓?span>INSERT璇彞鍦?span>user琛ㄤ腑鍔犲叆鏉$洰錛屽厑璁哥敤鎴?span>custom浠庡悇縐嶄富鏈虹敤緇欏畾鐨勫瘑鐮佽繘琛岃繛鎺ワ紝浣嗕笉鎺堜簣鍏ㄥ眬鏉冮檺(鎵鏈夋潈闄愯緗負(fù) 榛樿鍊?span>'N')銆傚悗闈?span>3涓?span>INSERT璇彞鍦?span>user琛ㄤ腑鍔犲叆鏉$洰錛屼負(fù)custom鎺堜簣bankaccount銆?span>expenses鍜?span>customer鏁版嵁搴撴潈闄愶紝浣嗗彧鑳戒粠鍚堥傜殑涓繪満璁塊棶銆?span>閫氬父鑻ョ洿鎺ヤ慨鏀?鎺堟潈琛紝鍒欏簲鍛婅瘔鏈嶅姟鍣ㄧ敤FLUSH PRIVILEGES閲嶈澆鎺堟潈琛紝浣挎潈闄愭洿鏀圭敓鏁堛?/span>
濡傛灉浣犳兂瑕佽鏌愪釜鐢ㄦ埛浠庣粰瀹氬煙鐨勬墍鏈夋満鍣ㄨ闂?span>(渚嬪錛?/span>mydomain.com)錛屼綘鍙互鍦ㄨ處鎴峰悕鐨勪富鏈洪儴鍒嗕嬌鐢ㄥ惈‘%’閫氶厤絎︾殑GRANT璇彞錛?/span>
mysql> GRANT ...
-> ON *.*
-> TO 'myname'@'%.mydomain.com'
-> IDENTIFIED BY 'mypass';
瑕佹兂閫氳繃鐩存帴淇敼鎺堟潈琛ㄦ潵瀹炵幇錛?/p>
mysql> INSERT INTO user (Host,User,Password,...)
-> VALUES('%.mydomain.com','myname',PASSWORD('mypass'),...);
mysql> FLUSH PRIVILEGES;