精华内容
下载资源
问答
  • 服务,在里面找到名称为mysql的项,双击就可看它的服务状态是启动还是停止,把它设为启动连接mysql:在命令行下输入 mysql -h localhost -u root -p回车,然后输入密码即可;或直接运行mysql自带的连接工具,然后输入密码...

    首要步骤(一般可省略):

    开启mysql服务(默认是开机时就自动运行了):

    控制面板-->管理工具-->服务,在里面找到名称为mysql的项,双击就可看它的服务状态是启动还是停止,把它设为启动

    连接mysql:

    在命令行下输入 mysql -h localhost -u root -p回车,然后输入密码即可;或直接运行mysql自带的连接工具,然后输入密码即可.

    1.编写sql脚本,假设内容如下:

    create database dearabao;

    use dearabao;

    create table niuzi (name varchar(20));

    保存脚本文件,假设我把它保存在F盘的hello world目录下,于是该文件的路径为:F:/hello world/niuzi.sql

    2.执行sql脚本,可以有2种方法:

    第一种方法:

    在命令行下(未连接数据库),输入 mysql -h localhost -u root -p123456 < F:/hello world/niuzi.sql (注意路径不用加引号的!!) 回车即可.

    第二种方法:

    在命令行下(已连接数据库,此时的提示符为 mysql> ),输入 source F:/hello world/niuzi.sql (注意路径不用加引号的) 或者 /. F:/hello world/niuzi.sql (注意路径不用加引号的) 回车即可

    SQL编写规范

    1.书写格式

    示例代码:

    存储过程SQL文书写格式例

    select

    c.dealerCode,

    round(sum(c.submitSubletAmountDLR + c.submitPartsAmountDLR + c.submitLaborAmountDLR) / count(*), 2) as avg,

    decode(null, 'x', 'xx', 'CNY')

    from (

    select

    a.dealerCode,

    a.submitSubletAmountDLR,

    a.submitPartsAmountDLR,

    a.submitLaborAmountDLR

    from SRV_TWC_F a

    where (to_char(a.ORIGSUBMITTIME, 'yyyy/mm/dd') >= 'Date Range(start)'

    and to_char(a.ORIGSUBMITTIME, 'yyyy/mm/dd') <= 'Date Range(end)'

    and nvl(a.deleteflag, '0') <> '1')

    union all

    select

    b.dealerCode,

    b.submitSubletAmountDLR,

    b.submitPartsAmountDLR,

    b.submitLaborAmountDLR

    from SRV_TWCHistory_F b

    where (to_char(b.ORIGSUBMITTIME, 'yyyy/mm/dd') >= 'Date Range(start)'

    and to_char(b.ORIGSUBMITTIME,'yyyy/mm/dd') <= 'Date Range(end)'

    and nvl(b.deleteflag,'0') <> '1')

    ) c

    group by c.dealerCode

    order by avg desc;

    Java source里的SQL字符串书写格式例

    strSQL = "insert into Snd_FinanceHistory_Tb "

    + "(DEALERCODE, "

    + "REQUESTSEQUECE, "

    + "HANDLETIME, "

    + "JOBFLAG, "

    + "FRAMENO, "

    + "INMONEY, "

    + "REMAINMONEY, "

    + "DELETEFLAG, "

    + "UPDATECOUNT, "

    + "CREUSER, "

    + "CREDATE, "

    + "HONORCHECKNO, "

    + "SEQ) "

    + "values ('" + draftInputDetail.dealerCode + "', "

    + "'" + draftInputDetail.requestsequece + "', "

    + "sysdate, "

    + "'07', "

    + "'" + frameNO + "', "

    + requestMoney + ", "

    + remainMoney + ", "

    + "'0', "

    + "0, "

    + "'" + draftStruct.employeeCode + "', "

    + "sysdate, "

    + "'" + draftInputDetail.honorCheckNo + "', "

    + index + ")";

    1).缩进

    对于存储过程文件,缩进为8个空格

    对于Java source里的SQL字符串,不可有缩进,即每一行字符串不可以空格开头

    2).换行

    1>.Select/From/Where/Order by/Group by等子句必须另其一行写

    2>.Select子句内容如果只有一项,与Select同行写

    3>.Select子句内容如果多于一项,每一项单独占一行,在对应Select的基础上向右缩进8个空格(Java source无缩进)

    4>.From子句内容如果只有一项,与From同行写

    5>.From子句内容如果多于一项,每一项单独占一行,在对应From的基础上向右缩进8个空格(Java source无缩进)

    6>.Where子句的条件如果有多项,每一个条件占一行,以AND开头,且无缩进

    7>.(Update)Set子句内容每一项单独占一行,无缩进

    8>.Insert子句内容每个表字段单独占一行,无缩进;values每一项单独占一行,无缩进

    9>.SQL文中间不允许出现空行

    10>.Java source里单引号必须跟所属的SQL子句处在同一行,连接符("+")必须在行首

    3).空格

    1>.SQL内算数运算符、逻辑运算符连接的两个元素之间必须用空格分隔

    2>.逗号之后必须接一个空格

    3>.关键字、保留字和左括号之间必须有一个空格

    2.不等于统一使用"<>"

    Oracle认为"!="和"<>"是等价的,都代表不等于的意义。为了统一,不等于一律使用"<>"表示

    3.使用表的别名

    数据库查询,必须使用表的别名

    4.SQL文对表字段扩展的兼容性

    在Java source里使用Select *时,严禁通过getString(1)的形式得到查询结果,必须使用getString("字段名")的形式

    使用Insert时,必须指定插入的字段名,严禁不指定字段名直接插入values

    5.减少子查询的使用

    子查询除了可读性差之外,还在一定程度上影响了SQL运行效率

    请尽量减少使用子查询的使用,用其他效率更高、可读性更好的方式替代

    6.适当添加索引以提高查询效率

    适当添加索引可以大幅度的提高检索速度

    请参看ORACLE SQL性能优化系列

    7.对数据库表操作的特殊要求

    本项目对数据库表的操作还有以下特殊要求:

    1).以逻辑删除替代物理删除

    注意:现在数据库表中数据没有物理删除,只有逻辑删除

    以deleteflag字段作为删除标志,deleteflag='1'代表此记录被逻辑删除,因此在查询数据时必须考虑deleteflag的因素

    deleteflag的标准查询条件:NVL(deleteflag, '0') <> '1'

    2).增加记录状态字段

    数据库中的每张表基本都有以下字段:DELETEFLAG、UPDATECOUNT、CREDATE、CREUSER、UPDATETIME、UPDATEUSER

    要注意在对标进行操作时必须考虑以下字段

    插入一条记录时要置DELETEFLAG='0', UPDATECOUNT=0, CREDATE=sysdate, CREUSER=登录User

    查询一条记录时要考虑DELETEFLAG,如果有可能对此记录作更新时还要取得UPDATECOUNT作同步检查

    修改一条记录时要置UPDATETIME=sysdate, UPDATEUSER=登录User, UPDATECOUNT=(UPDATECOUNT+1) mod 1000,

    删除一条记录时要置DELETEFLAG='1'

    3).历史表

    数据库里部分表还存在相应的历史表,比如srv_twc_f和srv_twchistory_f

    在查询数据时除了检索所在表之外,还必须检索相应的历史表,对二者的结果做Union(或Union All)

    8.用执行计划分析SQL性能

    EXPLAIN PLAN是一个很好的分析SQL语句的工具,它可以在不执行SQL的情况下分析语句

    通过分析,我们就可以知道ORACLE是怎样连接表,使用什么方式扫描表(索引扫描或全表扫描),以及使用到的索引名称

    按照从里到外,从上到下的次序解读分析的结果

    EXPLAIN PLAN的分析结果是用缩进的格式排列的,最内部的操作将最先被解读,如果两个操作处于同一层中,带有最小操作号的将首先被执行

    目前许多第三方的工具如PLSQL Developer和TOAD等都提供了极其方便的EXPLAIN PLAN工具

    PG需要将自己添加的查询SQL文记入log,然后在EXPLAIN PLAN中进行分析,尽量减少全表扫描

    ORACLE SQL性能优化系列

    1.选择最有效率的表名顺序(只在基于规则的优化器中有效)

    ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,因此FROM子句中写在最后的表(基础表driving table)将被最先处理

    在FROM子句中包含多个表的情况下,必须选择记录条数最少的表作为基础表

    当ORACLE处理多个表时,会运用排序及合并的方式连接它们

    首先,扫描第一个表(FROM子句中最后的那个表)并对记录进行排序;

    然后扫描第二个表(FROM子句中最后第二个表);

    最后将所有从第二个表中检索出的记录与第一个表中合适记录进行合并

    例如:

    表 TAB1 16,384 条记录

    表 TAB2 5 条记录

    选择TAB2作为基础表 (最好的方法)

    select count(*) from tab1,tab2 执行时间0.96秒

    选择TAB2作为基础表 (不佳的方法)

    select count(*) from tab2,tab1 执行时间26.09秒

    如果有3个以上的表连接查询,那就需要选择交叉表(intersection table)作为基础表,交叉表是指那个被其他表所引用的表

    例如:

    EMP表描述了LOCATION表和CATEGORY表的交集

    SELECT *

    FROM LOCATION L,

    CATEGORY C,

    EMP E

    WHERE E.EMP_NO BETWEEN 1000 AND 2000

    AND E.CAT_NO = C.CAT_NO

    AND E.LOCN = L.LOCN

    将比下列SQL更有效率

    SELECT *

    FROM EMP E ,

    LOCATION L ,

    CATEGORY C

    WHERE E.CAT_NO = C.CAT_NO

    AND E.LOCN = L.LOCN

    AND E.EMP_NO BETWEEN 1000 AND 2000

    2.WHERE子句中的连接顺序

    ORACLE采用自下而上的顺序解析WHERE子句

    根据这个原理,表之间的连接必须写在其他WHERE条件之前,那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾

    例如:

    (低效,执行时间156.3秒)

    SELECT *

    FROM EMP E

    WHERE SAL > 50000

    AND JOB = 'MANAGER'

    AND 25 < (SELECT COUNT(*) FROM EMP WHERE MGR=E.EMPNO);

    (高效,执行时间10.6秒)

    SELECT *

    FROM EMP E

    WHERE 25 < (SELECT COUNT(*) FROM EMP WHERE MGR=E.EMPNO)

    AND SAL > 50000

    AND JOB = 'MANAGER';

    3.SELECT子句中避免使用'*'

    当你想在SELECT子句中列出所有的COLUMN时,使用动态SQL列引用'*'是一个方便的方法,不幸的是,这是一个非常低效的方法

    实际上,ORACLE在解析的过程中,会将'*'依次转换成所有的列名

    这个工作是通过查询数据字典完成的,这意味着将耗费更多的时间

    4.减少访问数据库的次数

    当执行每条SQL语句时,ORACLE在内部执行了许多工作:解析SQL语句,估算索引的利用率,绑定变量,读数据块等等

    由此可见,减少访问数据库的次数,就能实际上减少ORACLE的工作量

    例如:

    以下有三种方法可以检索出雇员号等于0342或0291的职员

    方法1 (最低效)

    SELECT EMP_NAME, SALARY, GRADE

    FROM EMP

    WHERE EMP_NO = 342;

    SELECT EMP_NAME, SALARY, GRADE

    FROM EMP

    WHERE EMP_NO = 291;

    方法2 (次低效)

    DECLARE

    CURSOR C1 (E_NO NUMBER) IS

    SELECT EMP_NAME,SALARY,GRADE

    FROM EMP

    WHERE EMP_NO = E_NO;

    BEGIN

    OPEN C1(342);

    FETCH C1 INTO …,…,…;

    OPEN C1(291);

    FETCH C1 INTO …,…,…;

    CLOSE C1;

    END;

    方法2 (高效)

    SELECT A.EMP_NAME, A.SALARY, A.GRADE,

    B.EMP_NAME, B.SALARY, B.GRADE

    FROM EMP A, EMP B

    WHERE A.EMP_NO = 342

    AND B.EMP_NO = 291;

    5.使用DECODE函数来减少处理时间

    使用DECODE函数可以避免重复扫描相同记录或重复连接相同的表

    例如:

    SELECT COUNT(*), SUM(SAL)

    FROM EMP

    WHERE DEPT_NO = '0020'

    AND ENAME LIKE 'SMITH%';

    SELECT COUNT(*), SUM(SAL)

    FROM EMP

    WHERE DEPT_NO = '0030'

    AND ENAME LIKE 'SMITH%';

    你可以用DECODE函数高效地得到相同结果

    SELECT COUNT(DECODE(DEPT_NO, '0020', 'X', NULL)) D0020_COUNT,

    COUNT(DECODE(DEPT_NO, '0030', 'X', NULL)) D0030_COUNT,

    SUM(DECODE(DEPT_NO, '0020', SAL, NULL)) D0020_SAL,

    SUM(DECODE(DEPT_NO, 0030, SAL, NULL)) D0030_SAL

    FROM EMP

    WHERE ENAME LIKE 'SMITH%';

    'X'表示任何一个字段

    类似的,DECODE函数也可以运用于GROUP BY和ORDER BY子句中

    6.用Where子句替换HAVING子句

    避免使用HAVING子句,HAVING只会在检索出所有记录之后才对结果集进行过滤,这个处理需要排序、统计等操作

    如果能通过WHERE子句限制记录的数目,那就能减少这方面的开销

    例如:

    低效

    SELECT REGION, AVG(LOG_SIZE)

    FROM LOCATION

    GROUP BY REGION

    HAVING REGION REGION != 'SYDNEY'

    AND REGION != 'PERTH'

    高效

    SELECT REGION, AVG(LOG_SIZE)

    FROM LOCATION

    WHERE REGION REGION != 'SYDNEY'

    AND REGION != 'PERTH'

    GROUP BY REGION

    7.减少对表的查询

    在含有子查询的SQL语句中,要特别注意减少对表的查询

    例如:

    低效

    SELECT TAB_NAME

    FROM TABLES

    WHERE TAB_NAME = (SELECT TAB_NAME

    FROM TAB_COLUMNS

    WHERE VERSION = 604)

    AND DB_VER = (SELECT DB_VER

    FROM TAB_COLUMNS

    WHERE VERSION = 604)

    高效

    SELECT TAB_NAME

    FROM TABLES

    WHERE (TAB_NAME, DB_VER) = (SELECT TAB_NAME, DB_VER

    FROM TAB_COLUMNS

    WHERE VERSION = 604)

    Update多个Column例子:

    低效

    UPDATE EMP

    SET EMP_CAT = (SELECT MAX(CATEGORY)

    FROM EMP_CATEGORIES),

    SAL_RANGE = (SELECT MAX(SAL_RANGE)

    FROM EMP_CATEGORIES)

    WHERE EMP_DEPT = 0020;

    高效

    UPDATE EMP

    SET (EMP_CAT, SAL_RANGE) = (SELECT MAX(CATEGORY), MAX(SAL_RANGE)

    FROM EMP_CATEGORIES)

    WHERE EMP_DEPT = 0020;

    8.使用表的别名(Alias)

    当在SQL语句中连接多个表时,请使用表的别名并把别名前缀于每个Column上

    这样可以减少解析的时间并减少那些由Column歧义引起的语法错误

    9.用EXISTS替代IN

    在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接

    在这种情况下,使用EXISTS(或NOT EXISTS)通常将提高查询的效率

    低效

    SELECT *

    FROM EMP (基础表)

    WHERE EMPNO > 0

    AND DEPTNO IN (SELECT DEPTNO

    FROM DEPT

    WHERE LOC = 'MELB')

    高效

    SELECT *

    FROM EMP (基础表)

    WHERE EMPNO > 0

    AND EXISTS (SELECT 'X'

    FROM DEPT

    WHERE DEPT.DEPTNO = EMP.DEPTNO

    AND LOC = 'MELB')

    10.用NOT EXISTS替代NOT IN

    在子查询中,NOT IN子句将执行一个内部的排序和合并

    无论在哪种情况下,NOT IN都是最低效的,因为它对子查询中的表执行了一个全表遍历

    为了避免使用NOT IN,我们可以把它改写成外连接(Outer Joins)或NOT EXISTS

    例如:

    SELECT …

    FROM EMP

    WHERE DEPT_NO NOT IN (SELECT DEPT_NO

    FROM DEPT

    WHERE DEPT_CAT = 'A');

    为了提高效率改写为

    高效

    SELECT …

    FROM EMP A, DEPT B

    WHERE A.DEPT_NO = B.DEPT(+)

    AND B.DEPT_NO IS NULL

    AND B.DEPT_CAT(+) = 'A'

    最高效

    SELECT …

    FROM EMP E

    WHERE NOT EXISTS (SELECT 'X'

    FROM DEPT D

    WHERE D.DEPT_NO = E.DEPT_NO

    AND DEPT_CAT = 'A');

    11.用表连接替换EXISTS

    通常来说,采用表连接的方式比EXISTS更有效率

    例如:

    SELECT ENAME

    FROM EMP E

    WHERE EXISTS (SELECT 'X'

    FROM DEPT

    WHERE DEPT_NO = E.DEPT_NO

    AND DEPT_CAT = 'A');

    更高效

    SELECT ENAME

    FROM DEPT D, EMP E

    WHERE E.DEPT_NO = D.DEPT_NO

    AND DEPT_CAT = 'A';

    12.用EXISTS替换DISTINCT

    当提交一个包含多表信息(比如部门表和雇员表)的查询时,避免在SELECT子句中使用DISTINCT,一般可以考虑用EXIST替换

    例如:

    低效

    SELECT DISTINCT DEPT_NO, DEPT_NAME

    FROM DEPT D, EMP E

    WHERE D.DEPT_NO = E.DEPT_NO

    高效

    SELECT DEPT_NO, DEPT_NAME

    FROM DEPT D

    WHERE EXISTS (SELECT 'X'

    FROM EMP E

    WHERE E.DEPT_NO = D.DEPT_NO);

    EXISTS使查询更为迅速,因为RDBMS核心模块将在子查询的条件一旦满足后,立刻返回结果

    13.用索引提高效率

    索引是表的一个概念部分,用来提高检索数据的效率。实际上,ORACLE使用了一个复杂的自平衡B-tree结构

    通常,通过索引查询数据比全表扫描要快。当ORACLE找出执行查询和Update语句的最佳路径时,ORACLE优化器将使用索引

    同样,在联结多个表时使用索引也可以提高效率。另一个使用索引的好处是,它提供了主键(primary key)的唯一性验证

    除了那些LONG或LONG RAW数据类型,你可以索引几乎所有的列

    通常在大型表中使用索引特别有效,当然,在扫描小表时,使用索引同样能提高效率

    虽然使用索引能得到查询效率的提高,但是我们也必须注意到它的代价

    索引需要空间来存储,也需要定期维护,每当有记录在表中增减或索引列被修改时,索引本身也会被修改

    这意味着每条记录的INSERT、DELETE、UPDATE将为此多付出4、5次的磁盘I/O

    因为索引需要额外的存储空间和处理,那些不必要的索引反而会使查询反应时间变慢

    ORACLE对索引有两种访问模式:

    1).索引唯一扫描(INDEX UNIQUE SCAN)

    大多数情况下, 优化器通过WHERE子句访问INDEX

    例如:

    表LODGING有两个索引:建立在LODGING列上的唯一性索引LODGING_PK和建立在MANAGER列上的非唯一性索引LODGING$MANAGER

    SELECT *

    FROM LODGING

    WHERE LODGING = 'ROSE HILL';

    在内部,上述SQL将被分成两步执行:

    首先,LODGING_PK索引将通过索引唯一扫描的方式被访问,获得相对应的ROWID;然后通过ROWID访问表的方式执行下一步检索

    如果被检索返回的列包括在INDEX列中,ORACLE将不执行第二步的处理(通过ROWID访问表)

    因为检索数据保存在索引中,单单访问索引就可以完全满足查询结果

    2).索引范围查询(INDEX RANGE SCAN)

    适用于两种情况:

    1>.基于唯一性索引的一个范围的检索

    2>.基于非唯一性索引的检索

    例1

    SELECT LODGING

    FROM LODGING

    WHERE LODGING LIKE 'M%';

    WHERE子句条件包括一系列值,ORACLE将通过索引范围查询的方式查询LODGING_PK

    由于索引范围查询将返回一组值,它的效率就要比索引唯一扫描低一些

    例2

    SELECT LODGING

    FROM LODGING

    WHERE MANAGER = 'BILL GATES';

    这个SQL的执行分两步,LODGINGMANAGER的索引范围查询(得到所有符合条件记录的ROWID),通过ROWID访问表得到LODGING列的值由于LODGINGMANAGER的索引范围查询(得到所有符合条件记录的ROWID),通过ROWID访问表得到LODGING列的值由于LODGINGMANAGER是一个非唯一性的索引,数据库不能对它执行索引唯一扫描

    WHERE子句中,如果索引列所对应的值的第一个字符由通配符(WILDCARD)开始,索引将不被采用

    SELECT LODGING

    FROM LODGING

    WHERE MANAGER LIKE '%HANMAN';

    在这种情况下,ORACLE将使用全表扫描

    14.避免在索引列上使用计算

    WHERE子句中,如果索引列是函数的一部分,优化器将不使用索引而使用全表扫描

    例如:

    低效

    SELECT …

    FROM DEPT

    WHERE SAL * 12 > 25000;

    高效

    SELECT …

    FROM DEPT

    WHERE SAL > 25000/12;

    请务必注意,检索中不要对索引列进行处理,如:TRIM,TO_DATE,类型转换等操作,破坏索引,使用全表扫描,影响SQL执行效率

    15.避免在索引列上使用IS NULL和IS NOT NULL

    避免在索引中使用任何可以为空的列,ORACLE将无法使用该索引

    对于单列索引,如果列包含空值,索引中将不存在此记录;

    对于复合索引,如果每个列都为空,索引中同样不存在此记录。如果至少有一个列不为空,则记录存在于索引中

    如果唯一性索引建立在表的A列和B列上,并且表中存在一条记录的A,B值为(123,null),

    ORACLE将不接受下一条具有相同A,B值(123,null)的记录插入

    如果所有的索引列都为空,ORACLE将认为整个键值为空,而空不可能等于空,因此你可以插入1000条具有相同键值的记录,当然它们都是空!

    因为空值不存在于索引列中,所以WHERE子句中对索引列进行空值比较将使ORACLE停用该索引

    低效(索引失效)

    SELECT …

    FROM DEPARTMENT

    WHERE DEPT_CODE IS NOT NULL

    16.使用UNION-ALL和UNION

    当SQL语句需要UNION两个查询结果集合时,这两个结果集合会以UNION-ALL的方式被合并,然后在输出最终结果前进行排序

    如果用UNION ALL替代UNION,这样排序就不是必要了,效率就会因此得到提高

    需要注意的是,UNION ALL将重复输出两个结果集合中相同记录,因此还是要从业务需求分析使用UNION ALL的可行性

    关于索引下列经验请参考:

    1).如果检索数据量超过30%的表中记录数,使用索引将没有显著的效率提高

    2).在特定情况下,使用索引也许会比全表扫描慢,但这是同一个数量级上的差距;而通常情况下,使用索引比全表扫描要快几倍乃至几千倍!

    其他具体内容请参考《ORACLE SQL性能优化系列》

    17.使用PrepareStatement

    在同一个方法中,当循环使用SQL文时,为了提高性能,

    请使用PreparedStatement。注意,

    仅限使用于少数的模块。

    方法如下:

    ? PreparedStatement stmt

    = conn.prepareStatement("select a from TABLE_A where b=? c=?");

    for(?? ){

    ???? stmt.setInt(1, varB);

    ???? stmt.setString(2, varC);

    ?   ResultSet rst = stmt.executeQuery();

    }

    f68f2add0b68e4f9810432fce46917b7.png

    本文原创发布php中文网,转载请注明出处,感谢您的尊重!

    展开全文
  • 在为mysql-proxy编写lua脚步的时候,需要知道一下几个入口函数,通过这几个入口函数我们可以控制mysql-proxy的一些行为。connect_server() 当代理服务器接受到客户端连接请求时(tcp中的握手)会调用该函数read_...

    在为mysql-proxy编写lua脚步的时候,需要知道一下几个入口函数,通过这几个入口函数我们可以控制mysql-proxy的一些行为。

    connect_server()          当代理服务器接受到客户端连接请求时(tcp中的握手)会调用该函数

    read_handshake()        当mysql服务器返回握手相应时会被调用

    read_auth()             当客户端发送认证信息(username,password,port,database)时会被调用

    read_auth_result(aut)  当mysql返回认证结果时会被调用

    read_query(packet)      当客户端提交一个sql语句时会被调用

    read_query_result(inj) 当mysql返回查询结果时会被调用

    1.connect_server使用

    functionread_handshake( )local con =proxy.connectionprint("

    -- lets deny clients from !127.0.0.1

    if con.client.src.address ~= "127.0.0.1" then

    proxy.response.type = proxy.MYSQLD_PACKET_ERR

    proxy.response.errmsg = "only local connects are allowed"

    print("we don't like this client");

    return proxy.PROXY_SEND_RESULT

    end

    end

    获取代理的链接对象,这个对象是全局的,可以在函数中直接拿来使用。从连接对象中我们可以拿到客户端名称和服务器名称,通过也能获得客户端的ip地址,上面的代码就是禁止非本机ip登录mysql。

    2、read_auth使用

    读取用户的认证信息包括用户名、密码、所要连接的数据库。其中的proxy.MYSQLD_PACKET_ERR是mysql-proxy中自带的常量。

    functionread_auth( )local con =proxy.connectionprint("--> there, look, the client is responding to the server auth packet")print("username :".. con.client.username)print("password :" .. string.format("%q", con.client.scrambled_password))print("default_db :".. con.client.default_db)if con.client.username == "evil" thenproxy.response.type =proxy.MYSQLD_PACKET_ERR

    proxy.response.errmsg= "evil logins are not allowed"

    returnproxy.PROXY_SEND_RESULTend

    end

    3.read_auth_result使用

    通过该方法我们可以获得mysql数据库的认证结果,认证结果由auth对象持有,我们可以访问其packet属性(字符串类型),可以查看返回结果。字符串的第一个字符是对结果的标识。

    functionread_auth_result( auth )local state =auth.packet:byte() //获取第一个字符并将其转为整型if state == proxy.MYSQLD_PACKET_OK then

    print("

    print("

    print("

    end

    4.read_query的使用

    packet中就存放着客户请求的SQL语句,类型为字符串类型。起始第一个字符同上,为标识符。这里判断是不是一个查询语句,是的话就从第二个字符开始输出查询语句。

    functionread_query( packet )print("--> someone sent us a query")if packet:byte() == proxy.COM_QUERY then

    print("query:" .. packet:sub(2))if packet:sub(2) == "SELECT 1" thenproxy.queries:append(1, packet)end

    end

    end

    5、read_query_result使用

    其实我们该函数和read_query函数时是希望对SQL语句进行处理,但是由于时间有限,不能对mysql-proxy提供的sql处理继续研究,这里先就先贴出来。

    functionread_query_result( inj )print("

    proxy.response={type =proxy.MYSQLD_PACKET_RAW,

    packets={"\255".."\255\004" .. --errno

    "#".."12S23".."raw, raw, raw"}

    }returnproxy.PROXY_SEND_RESULTend

    8f900a89c6347c561fdf2122f13be562.png

    961ddebeb323a10fe0623af514929fc1.png

    --[[$%BEGINLICENSE%$

    Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved.

    This program is free software; you can redistribute it and/or

    modify it under the terms of the GNU General Public License as

    published by the Free Software Foundation; version 2 of the

    License.

    This program is distributed in the hope that it will be useful,

    but WITHOUT ANY WARRANTY; without even the implied warranty of

    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License

    along with this program; if not, write to the Free Software

    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA

    02110-1301 USA

    $%ENDLICENSE%$ --]]

    local proto = require("mysql.proto")local prep_stmts ={ }functionread_query( packet )local cmd_type =packet:byte()if cmd_type == proxy.COM_STMT_PREPARE thenproxy.queries:append(1, packet, { resultset_is_needed = true} )returnproxy.PROXY_SEND_QUERYelseif cmd_type == proxy.COM_STMT_EXECUTE thenproxy.queries:append(2, packet, { resultset_is_needed = true} )returnproxy.PROXY_SEND_QUERYelseif cmd_type == proxy.COM_STMT_CLOSE thenproxy.queries:append(3, packet, { resultset_is_needed = true} )returnproxy.PROXY_SEND_QUERYend

    end

    functionread_query_result(inj)if inj.id == 1 then

    --print the query we sent

    local stmt_prepare = assert(proto.from_stmt_prepare_packet(inj.query))print(("> PREPARE: %s"):format(stmt_prepare.stmt_text))--and the stmt-id we got for it

    if inj.resultset.raw:byte() == 0 then

    local stmt_prepare_ok = assert(proto.from_stmt_prepare_ok_packet(inj.resultset.raw))print(("< PREPARE: stmt-id = %d (resultset-cols = %d, params = %d)"):format(

    stmt_prepare_ok.stmt_id,

    stmt_prepare_ok.num_columns,

    stmt_prepare_ok.num_params))

    prep_stmts[stmt_prepare_ok.stmt_id]={

    num_columns=stmt_prepare_ok.num_columns,

    num_params=stmt_prepare_ok.num_params,

    }end

    elseif inj.id == 2 then

    local stmt_id = assert(proto.stmt_id_from_stmt_execute_packet(inj.query))local stmt_execute = assert(proto.from_stmt_execute_packet(inj.query, prep_stmts[stmt_id].num_params))print(("> EXECUTE: stmt-id = %d"):format(stmt_execute.stmt_id))if stmt_execute.new_params_bound then

    for ndx, v in ipairs(stmt_execute.params) do

    print(("[%d] %s (type = %d)"):format(ndx, tostring(v.value), v.type))end

    end

    elseif inj.id == 3 then

    local stmt_close = assert(proto.from_stmt_close_packet(inj.query))print(("> CLOSE: stmt-id = %d"):format(stmt_close.stmt_id))

    prep_stmts[stmt_close.stmt_id]= nil --cleanup

    end

    end

    View Code

    这里使用了MySQL新的接口stmt,对其不了解可以查看下面的连接。

    展开全文
  • 假设,MySQL连接信息如下: host: 192.168.1.4 port: 3306 user: root password: mypassword 现在,我们需要对这台服务器上的数据库进行备份。从MySQL导出数据需要用到mysqldump工具,不论写不写Python脚本。 一...

    假设,MySQL的连接信息如下:

    • host: 192.168.1.4
    • port: 3306
    • user: root
    • password: mypassword

    现在,我们需要对这台服务器上的数据库进行备份。从MySQL导出数据需要用到mysqldump工具,不论写不写Python脚本。

    一、不编写Python脚本

    备份全部数据库数据到一个sql文件(包括了mysql、sys、information_schema、performance_schema等内置数据库):

    mysqldump -h192.168.1.4 -uroot -pmypassword -A > mysql_backup.sql
    

    排除掉指定数据库,并备份其他所有数据库数据到一个sql文件:

    mysql -e "show databases;" -h192.168.1.4 -uroot -pmypassword | grep -Ev "Database|mysql|sys|information_schema|performance_schema" | xargs mysqldump -h192.168.1.4 -uroot -pmypassword --databases > mysql_backup.sql
    

    备份指定的几个数据库(假设要备份两个数据库,名称分别为db1和db2)数据到一个文件:

    mysqldump -h192.168.1.4 -uroot -pmypassword --databases db1 db2 > mysql_backup.sql
    

    一般来说,不用编写Python脚本,只在命令行中使用mysqldump就能完成一键备份的功能。

    二、编写Python脚本

    那我还编写Python脚本干嘛?

    emmm,主要是想灵活一点,比如我想把每个数据库单独备份成一个sql文件,并都保存在同一个目录下面。想达到这个目的,要么手动执行很多条命令,要么就编写脚本。写脚本并不限制用什么语言,写个shell脚本也没问题,不过我更习惯用Python,所以我用Python来写。

    # -*- coding: utf-8 -*-
    # @File  : mysql_backup.py
    # @Author: AaronJny
    # @Date  : 2019/11/19
    # @Desc  : 使用Python脚本,批量备份MySQL数据库结构和数据
    import logging
    import os
    import subprocess
    import pymysql
    
    # 设置日志输出格式
    logging.basicConfig(format='%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s',
                        level=logging.INFO)
    
    # MySQL数据库用户名
    MYSQL_USERNAME = 'root'
    # 数据库密码
    MYSQL_PASSWORD = 'mypassword'
    # 数据库主机地址
    MYSQL_HOST = '192.168.1.4'
    # 数据库端口
    MYSQL_PORT = 3306
    # 备份文件存放路径
    BACKUP_PATH = 'backup'
    # 排除,不进行备份操作的数据库名称集合
    DISABLED_DATABASES = {'information_schema', 'mysql', 'performance_schema', 'sys'}
    
    
    def mkdir_if_not_exists(path):
        """
        判断给定目录是否存在,不存在则创建它
    
        Args:
            path: 带创建目录名称
        """
        if not os.path.exists(path):
            os.mkdir(path)
    
    
    def create_mysql_conn(db='mysql'):
        """
        创建并返回一个mysql数据库连接
    
        Args:
            db: 要连接的数据库名称
    
        Returns:
    
        """
        conn = pymysql.connect(host=MYSQL_HOST, port=MYSQL_PORT, user=MYSQL_USERNAME, password=MYSQL_PASSWORD, db='mysql')
        return conn
    
    
    def read_all_databases():
        """
        从数据库中读取全部数据库名称
    
        Returns:
            list,数据库名称列表
        """
        logging.info('读取全部数据库名称...')
        conn = create_mysql_conn()
        cursor = conn.cursor()
        # 查询服务器上有哪些数据库
        cursor.execute('show databases')
        res = cursor.fetchall()
        databases = {item[0] for item in res}
        # 排除掉指定不备份的数据库
        databases = list(databases - DISABLED_DATABASES)
        cursor.close()
        conn.close()
        logging.info('读取完毕,数据库列表如下:{}'.format(databases))
        return databases
    
    
    def backup_database(database):
        """
        备份指定数据库的数据和表结构
    
        Args:
            database: 待备份的数据库名称
        """
        logging.info('开始备份数据库 {}...'.format(database))
        # 通过调用mysqldump完成指定数据库的备份
        command = 'mysqldump -h192.168.1.4 -uroot -p666 --add-drop-database --databases {database} > {backup_path}/{database}.sql'.format(
            database=database,
            backup_path=BACKUP_PATH)
        exit_code = subprocess.call(command, shell=True)
        # 判断命令是否正常执行,异常则直接抛出
        if exit_code != 0:
            raise Exception('在备份数据库的过程中出错,请检查!')
        logging.info('数据库 {} 备份完毕!'.format(database))
    
    
    def backup():
        """
        读取全部数据库名称,并对这些数据库的数据和结构进行备份
        """
        # 检查备份路径是否存在,不存在则进行创建
        mkdir_if_not_exists(BACKUP_PATH)
        # 读取全部待备份数据库名称
        databases = read_all_databases()
        # 逐个对数据库进行备份
        for database in databases:
            backup_database(database)
    
    
    if __name__ == '__main__':
        backup()
    
    

    代码有写注释,就不多说了,直接看代码吧。简单配置一下,并执行这个脚本,即可一键备份数据库到指定路径。

    如果我们想使用备份的数据恢复数据库怎么办呢?我们再编写一个恢复用的脚本。注意,备份的数据库服务器,和恢复的数据库服务器,可以不是同一台服务器,所以这个脚本也可以用于数据库迁移的场景。

    另外,请注意,当目标数据库中已经有同名的数据库了,会先删除同名数据库,再重新创建并恢复数据。请确认这个逻辑是否和你的需求相符,并谨慎操作。

    # -*- coding: utf-8 -*-
    # @File  : mysql_recovery.py
    # @Author: AaronJny
    # @Date  : 2019/11/19
    # @Desc  : 使用Python脚本,使用备份的MySQL数据库结构和数据进行恢复
    import logging
    import os
    import subprocess
    import pymysql
    
    # 设置日志输出格式
    logging.basicConfig(format='%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s',
                        level=logging.INFO)
    
    # MySQL数据库用户名
    MYSQL_USERNAME = 'root'
    # 数据库密码
    MYSQL_PASSWORD = 'mypassword'
    # 数据库主机地址
    MYSQL_HOST = '192.168.1.4'
    # 数据库端口
    MYSQL_PORT = 3306
    # 备份文件存放路径
    BACKUP_PATH = 'backup'
    
    logging.info('开始获取需要恢复的数据库文件...')
    files = list(os.listdir(BACKUP_PATH))
    
    logging.info('文件列表:{}'.format(files))
    
    # 开始逐个恢复数据库
    for file in files:
        logging.info('开始恢复数据库 {}...'.format(file.split('.')[0]))
        command = 'mysql -h{host} -f -u{user} -p{password} -P{port} < {path}/{file}'.format(host=MYSQL_HOST,
                                                                                            user=MYSQL_USERNAME,
                                                                                            password=MYSQL_PASSWORD,
                                                                                            port=MYSQL_PORT, file=file,
                                                                                            path=BACKUP_PATH)
        subprocess.call(command, shell=True)
    logging.info('完毕!')
    
    

    好的,大功告成!


    参考文章:

    mysqldump导出多数据库操作

    展开全文
  • 环境开发包:appserv-win32-2.5.10服务器:Apache2.2数据库:phpMyAdmin语言:php5,java平台:windows 10java驱动:mysql-connector-java-5.1.37需求编写一个PHP脚本语言,连接到phpMyAdmin数据库的test库编写一个...

    环境

    开发包:appserv-win32-2.5.10

    服务器:Apache2.2

    数据库:phpMyAdmin

    语言:php5,java

    平台:windows 10

    java驱动:mysql-connector-java-5.1.37

    需求

    编写一个PHP脚本语言,连接到phpMyAdmin数据库的test库

    编写一个java web服务端,连接到phpMyAdmin数据库的test库

    代码

    php连接方式

    mysql.php

    /*****************************

    *数据库连接

    *****************************/

    $conn= @mysql_connect("localhost","root","123");

    if(!$conn){

    die("连接数据库失败:" .mysql_error());

    }

    mysql_select_db("test",$conn);

    //字符转换,读库

    mysql_query("set character set utf8");

    mysql_query("set names utf8");

    ?>

    test.php测试

    error_reporting(0);//防止报错

    include('mysql.php');

    $result=mysql_query("select * from user");//根据前面的计算出开始的记录和记录数

    //循环取出记录

    $six;

    while($row=mysql_fetch_row($result))

    {

    echo$row[0];

    echo$row[1];

    }

    ?>

    运行截图:

    java连接方式

    1.新建一个java project为mysqlTest

    2.加载JDBC驱动,mysql-connector-java-5.1.37

    MySQLConnection.java

    packagecom.mysqltest;

    importjava.sql.Connection;

    importjava.sql.DriverManager;

    importjava.sql.SQLException;

    /*

    * **Mysql连接**

    *

    *参数:

    * conn连接

    * url mysql数据库连接地址

    * user数据库登陆账号

    * password数据库登陆密码

    *方法:

    * conn获取连接

    */

    publicclassMySQLConnection {

    publicstaticConnection conn =null;

    publicstaticString driver ="com.mysql.jdbc.Driver";

    publicstaticString url ="jdbc:mysql://127.0.0.1:3306/post";

    publicstaticString user ="root";

    publicstaticString password ="123";

    /*

    *创建Mysql数据连接第一步:加载驱动Class.forName(Driver)第二步:创建连接

    *DriverManager.getConnection(url, user, password);

    */

    publicConnection conn() {

    try{

    Class.forName(driver);

    }catch(ClassNotFoundException e) {

    System.out.println("驱动加载错误");

    e.printStackTrace();

    }

    try{

    conn = DriverManager.getConnection(url, user, password);

    }catch(SQLException e) {

    System.out.println("数据库链接错误");

    e.printStackTrace();

    }

    returnconn;

    }

    }

    Work.java

    packagecom.mysqltest;

    importjava.sql.Connection;

    importjava.sql.PreparedStatement;

    importjava.sql.ResultSet;

    importjava.sql.SQLException;

    /*

    * mysql增删改查

    */

    publicclassWork {

    /*

    * insert增加

    */

    publicstaticintinsert() {

    MySQLConnection connection =newMySQLConnection();

    Connection conns;//获取连接

    PreparedStatement pst;//执行Sql语句

    inti = 0;

    String sql = "insert into user (username,password)values(?,?)";

    try{

    conns = connection.conn();

    pst = conns.prepareStatement(sql);

    pst.setString(1, "lizi");

    pst.setString(2, "123");

    i= pst.executeUpdate();

    pst.close();

    conns.close();

    }catch(SQLException e) {

    System.out.println("数据写入失败");

    e.printStackTrace();

    }

    returni;

    }

    /*

    * select写入

    */

    publicstaticvoidselect() {

    MySQLConnection connection =newMySQLConnection();

    Connection conns;//获取连接

    PreparedStatement pst;//执行Sql语句(Statement)

    ResultSet rs;//获取返回结果

    String sql = "select * from user";

    try{

    conns = connection.conn();

    pst = conns.prepareStatement(sql);

    rs = pst.executeQuery(sql);//执行sql语句

    System.out.println("---------------------------------------");

    System.out.println("名字|密码");

    while(rs.next()) {

    System.out.println(rs.getString("username") + "        |       " + rs.getString("password"));

    }

    System.out.println("---------------------------------------");

    conns.close();

    pst.close();

    rs.close();

    }catch(SQLException e) {

    System.out.println("数据查询失败");

    e.printStackTrace();

    }

    }

    /*

    * update修改

    */

    publicstaticintupdate() {

    MySQLConnection connection =newMySQLConnection();

    Connection conns;//获取连接

    PreparedStatement pst;//执行Sql语句(Statement)

    inti = 0;

    String sql = "update user set password = ? where username =?";

    try{

    conns = connection.conn();

    pst = conns.prepareStatement(sql);

    pst.setString(1, "123");

    pst.setString(2, "lizi");

    i= pst.executeUpdate();

    pst.close();

    conns.close();

    }catch(SQLException e) {

    System.out.println("数据修改失败");

    e.printStackTrace();

    }

    returni;

    }

    /*

    * delete删除

    */

    publicstaticintdelete() {

    MySQLConnection connection =newMySQLConnection();

    Connection conns;//获取连接

    PreparedStatement pst;//执行Sql语句(Statement)

    inti = 0;

    String sql = "delete from user where username = ?";

    try{

    conns = connection.conn();

    pst = conns.prepareStatement(sql);

    pst.setString(1, "lizi");

    i= pst.executeUpdate();

    pst.close();

    conns.close();

    }catch(SQLException e) {

    System.out.println("数据删除失败");

    e.printStackTrace();

    }

    returni;

    }

    /*

    * test

    */

    publicstaticvoidmain(String[] args) {

    //System.out.println(insert());

    select();

    //System.out.println(update());

    // System.out.println(delete());

    }

    }

    展开全文
  • 是模拟客户端去连接...而数据库只能利用ODBC协议来录制(编写)脚本,所以必须要MySql的ODBC驱动,和支持ODBC的查询分析器(录脚本需要,自己编写就不需要)。pMjU2`oFs720471、首先要安装MySql的ODBC驱动,MyODBC ...
  • MySQL--执行mysql脚本及其脚本编写

    千次阅读 2019-01-08 09:02:23
    首要步骤(一般可省略):开启mysql服务(默认是开机时就自动运行了):控制面板--&gt;管理工具--&gt;服务,在里面找到名称为mysql的项,双击就可看它的服务状态是启动还是停止,把它设为启动 ...1.编写sql脚本,假设...
  • Mysql系列 (八) 编写脚本

    千次阅读 2016-05-18 16:34:44
    首要步骤(一般可省略): 开启mysql服务(默认是开机时就自动运行了): ...连接mysql: 在命令行下输入 mysql -h localhost -u root -p回车,然后输入密码即可;或直接运行mysql自带的连接工具,然后输入密码即可. 1.编写sql脚
  • 最近做了几周的LoadRunner测试,有一些心得,记录下来,以便以后查找。 LoadRunner测试数据库是模拟客户端去连接数据库服务器,因此,...而MySQL数据库只能利用ODBC协议来录制(编写脚本,所以必须要MySql的ODB...
  • 环境开发包:appserv-win32-2.5.10服务器:Apache2.2数据库:phpMyAdmin语言:php5,java平台:windows 10java驱动:mysql-connector-java-5.1.37需求编写一个PHP脚本语言,连接到phpMyAdmin数据库的test库编写一个...
  • python脚本第一次写博客,已经工作一年半了,从事PHP后端,最近尝试新语言,换换胃口,看了看go和python,最后选择了python。...连接mysql连接mysql有很多种方式:pymysql mysql-connector mysqldb。之...
  • 编写一个PHP脚本语言,连接到phpMyAdmin数据库的test库 编写一个java web服务端,连接到phpMyAdmin数据库的test库 代码 php连接方式 mysql.php <?php /***************************** *数据库连接 *************...
  • 环境开发包:appserv-win32-2.5.10服务器:Apache2.2数据库:phpMyAdmin语言:php5,java平台:windows 10java驱动:mysql-connector-java-5.1.37需求编写一个PHP脚本语言,连接到phpMyAdmin数据库的test库编写一个...
  • LoadRunner测试数据库是模拟客户端去连接数据库...而MySql数据库只能利用ODBC协议来录制(编写)脚本,所以必须要MySql的ODBC驱动,和支持ODBC的查询分析器(录脚本需要,自己编写就不需要)。1、首先要安装MySql的OD...
  • 编写 test_conn.py 脚本,内容: import pymysql # localhost 可以修改为 IP地址,如 10.36.172.34 # 3306是当前主机的端口,不是容器的端口 conn = pymysql.Connect(host="localhost", port=3306, user="root", ...
  • 本文原创,欢迎转载。转载请在文章明显可见处张贴如下内容:(注意:请保留超链接格式) 本文为Rainisic原创,欢迎转载,转载请在文章明显可见处张贴原帖信息: ...1. 编写Shell脚本 #! /bin/sh /usr/local/...
  • 服务,在里面找到名称为mysql的项,双击就可看它的服务状态是启动还是停止,把它设为启动连接mysql:在命令行下输入 mysql -h localhost -u root -p回车,然后输入密码即可;或直接运行mysql自带的连接工具,然后输入密码...
  • 分享给大家供大家参考,具体如下:命令行连接在工作中主要使用命令操作方式,要求熟练编写打开终端,运行命令mysql -uroot -p回车后输入密码,当前设置的密码为mysql连接成功后如下图退出登录quit 和 exit或ctrl+d...
  • LoadRunner测试数据库是模拟客户端去连接数据库服务器,因此,...而MySql数据库只能利用ODBC协议来录制(编写脚本,所以必须要MySql的ODBC驱动,和支持ODBC的查询分析器(录脚本需要,自己编写就不需要)。 1、...
  • JDBC连接数据库参考:https://www.cnblogs.com/ysgcs/p/7283701.html 注册驱动:告诉程序连接哪个数据库,通过驱动jar包连接 添加驱动jar包 添加到工程环境变量:右键→Build Path→Add to Build Path ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 456
精华内容 182
关键字:

编写脚本连接mysql

mysql 订阅