【997755.com澳门葡京】浅谈Mybatis连接原理,JDBC入门整理

     
 无人不知数据库连接的经过,不过近期面试的人(菜面菜),都说用的SSM框架,不过本身问了一晃,mybatis是怎么总是上mysql的,基本上都会说:配置好的,直接用了,后天本人来引玉之砖一下,欢迎拍砖!

原文链接:

JDBC入门(1),jdbc入门

   JDBC(Java DataBase
Connectivity,java数据库连日来)是一种用于实施SQL语句的Java
API,可以为各类关周全据库提供联合访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种规格,据此可以构建更高级的工具和接口,使数据库开发人士可以编写数据库应用程序,同时,JDBC也是个商标名。

一、Java连接数据库示例:

1、步骤:

  • 导jar包:驱动。
  • 加载驱动类:Class.forName(“类名”);
  • 给出url、username、password,其中url背下来。
  • 利用DriverManager类来博取Connection对象。

 1 public class Demo1 {
 2     /**
 3      * ClassNotFoundException:
 4      * 没有导入驱动包
 5      *
 6      * SQLException:
 7      *  检查三个参数:url、username、password是否正确
 8      *  检查是否开启了mysql服务器。
 9      *
10      */
11     @Test
12     public void fun1() throws ClassNotFoundException,SQLException{
13         /**
14          * jdbc四大配置参数
15          *   driverClassName:com.mysql.jdbc.Driver
16          *   url:jdbc:mysql://localhost:3306/数据库名
17          *   username:root
18          *   password:
19          */
20         Class.forName("com.mysql.jdbc.Driver");//加载驱动类(注册驱动)
21 
22         //使用url、username、password,得到连接对象
23         Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb_1","root","");
24         System.out.println(con);
25     }
26 }

2、基本极度

未导驱动包:java.lang.ClassNotFoundException: com.mysql.jdbc.Driver ;

数据库不存在:com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:
Unknown database ‘mydb’;

端口错误:com.mysql.jdbc.exceptions.jdbc4.CommunicationsException:
Communications link failure;

密码错误:java.sql.SQLException: Access denied for user
‘root’@’localhost’ (using password: YES);

用户不设有:java.sql.SQLException: Access denied for user
‘root’@’localhost’ (using password: YES);

二、JDBC原理

Class.forName("com.mysql.jdbc.Driver");//此据等同于以下面两句,与最后一句的逻辑关系
com.mysql.jdbc.Driver driver = new com.mysql.jdbc.Driver;
DriverManager.registerDriver(driver);
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb_1","root","");

  所有的java.sql.Driver完成类,都提供了static块,块内的代码就是把自身注册到DriverManage中,如com.mysql.jdbc.Driver中的部分源码:

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    //
    // Register ourselves with the DriverManager
    //
    static {
        try {
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
    }

    /**
     * Construct a new driver and register it with DriverManager
     * 
     * @throws SQLException
     *             if a database error occurs.
     */
    public Driver() throws SQLException {
        // Required for Class.forName().newInstance()
    }
}

  JDBC
4.0将来,每一种驱动jar包中,在META-INF/services目录下提供了一个名为java.sql.Driver的文本,文件的情节就是该接口的落到实处类名称。连接数据库例子中,第20行“Class.forName(“com.mysql.jdbc.Driver”);”可省略不写。

三、使用JDBC对数据库举行不难的增删改查操作示例

  1 package demo2;
  2 
  3 import org.junit.Test;
  4 import java.sql.*;
  5 
  6 public class Demo2 {
  7     /*
  8     * 对数据库进行增、删、改操作
  9     * */
 10     @Test
 11     public void fun1() throws ClassNotFoundException,SQLException {
 12         /*
 13         * 一、得到Connection
 14         * 1、准备四个参数
 15         * 2、加载驱动类
 16         * 3、得到Connection
 17         * */
 18 
 19         String driverClassName = "com.mysql.jdbc.Driver";
 20         //jdbc协议的格式,jdbc:工商的名称:子协议(由工商自己来规定)
 21         //对mysql而言,它的子协议结构://主机:端口号/数据库名称
 22         String url = "jdbc:mysql://localhost:3306/mydb1";
 23         String username = "root";
 24         String password = "";
 25         //加载驱动类
 26         Class.forName(driverClassName);
 27         //使用DriverManager,以及剩下的三个参数,得到Connection
 28         Connection con = DriverManager.getConnection(url, username, password);
 29         /*
 30         * 二、对数据库做增删改
 31         *1、通过Connection对象创建Statement
 32         *  Statement 语句的发送器,它的功能就是向数据库发送sql语句,
 33         *2、调用它的int executeUpdate(String sql),它可以发送DML、DDL
 34         * */
 35         Statement stmt = con.createStatement();
 36 //        String sql = "INSERT INTO stu VALUES('0003','wangwu',88,'male')";
 37 //        String sql = "UPDATE stu SET name='zhaoliu',age=22,gender='female' WHERE " +
 38 //                "number='0003'";
 39         String sql = "DELETE FROM stu";
 40         int r = stmt.executeUpdate(sql);
 41         System.out.println(r);
 42     }
 43     /*
 44      * 执行查询操作
 45      * */
 46      @Test
 47     public void fun2() throws ClassNotFoundException,SQLException {
 48 
 49          /*
 50          * 一、得到Connection
 51          * 二、得到Statement,发送select语句
 52          * 三、对查询返回的"表格"进行解析
 53          * */
 54          /*
 55          * 一、得到连接
 56          * */
 57          String driverClassName = "com.mysql.jdbc.Driver";
 58          String url = "jdbc:mysql://localhost:3306/mydb1";
 59          String username = "root";
 60          String password = "";
 61 
 62          Class.forName(driverClassName);
 63          Connection con = DriverManager.getConnection(url,username,password);
 64          /*
 65          * 二、得到Statement,执行select语句
 66          * */
 67          Statement stmt = con.createStatement();
 68          /*
 69          *调用Statement的ResultSet rs = executeQuery(String querySql);
 70          * */
 71          ResultSet rs = stmt.executeQuery("SELECT * FROM emp");
 72          /*
 73          * 三、解析ResultSet
 74          * 1、把行光标移动到第一行,可以调用next()方法完成。
 75          * */
 76          while (rs.next()) { //把光标向下移动一行,并判断下一行是否存在
 77              int empno = rs.getInt(1);//通过列编号来获取该列的值
 78              String ename = rs.getString("ename");//通过列名称来获取该列的值
 79              double sal = rs.getDouble("sal");
 80 
 81              System.out.println(empno+","+ename+","+sal);
 82          }
 83          /*
 84          * 四、关闭资源
 85          * 倒关
 86          * */
 87          rs.close();
 88          stmt.close();
 89          con.close();//必须关,不关就死。
 90     }
 91     //规范化
 92     @Test
 93     public void fun3() throws Exception {
 94         Connection con = null;//定义引用
 95         Statement stmt = null;
 96         ResultSet rs = null;
 97         try {
 98             //一、得到Connection
 99             String driverClassName  = "com.mysql.jdbc.Driver";
100             String url = "jdbc:mysql://localhost:3306/mydb1";
101             String username = "root";
102             String password = "";
103             Class.forName(driverClassName);
104             con = DriverManager.getConnection(url,username,password);//实例化
105             //二、创建Statement
106             stmt = con.createStatement();
107             String sql = "SELECT * FROM emp";
108             rs = stmt.executeQuery(sql);//实例化
109             //三、循环遍历rs,打印其中数据
110             //getString()和getObject()是通用的
111             int count = rs.getMetaData().getColumnCount();
112             while (rs.next()) {
113                 for (int i = 1; i <= count; i++) {
114                     System.out.print(rs.getString(i));
115                     if (i<count) {
116                         System.out.print(",");
117                     }
118                 }
119                 System.out.println();
120             }
121 
122         } catch (Exception e) {
123             throw new RuntimeException(e);
124         } finally {
125             //为了防止空指针异常发生,使用判断语句
126             if(rs != null) rs.close();
127             if(stmt != null) stmt.close();
128             if(con != null) con.close();
129         }
130     }
131 }

 

JDBC(Java DataBase
Connectivity,java数据库连续)是一种用于实践SQL语句的Java
API,可以为八种关周全据库提供联合访问,…

JDBC入门

【997755.com澳门葡京】浅谈Mybatis连接原理,JDBC入门整理。l  导jar包:驱动!

l  加载驱动类:Class.forName(“类名”);

l  给出url、username、password,

l  使用DriverManager类来拿到Connection对象!

 

 

 

       什么是JDBC?

什么是JDBC?

1 什么是JDBC(接口,完成为使得)

  JDBC(Java DataBase
Connectivity)就是Java数据库连接,说白了就是用Java语言来操作数据库。原来我们操作数据库是在控制台使用SQL语句来操作数据库,JDBC是用Java语言向数据库发送SQL语句。

 

       Java语言访问数据库的一种标准,是一套API。JDBC (Java Database
Connectivity)
API,即Java数据库编程接口,是一组正式的Java语言中的接口和类,使用那些接口和类,Java客户端程序能够访问各类分歧品类的数据库。JDBC规范应用接口和贯彻分离的合计设计了Java数据库编程的框架。接口包罗在java.sql及javax.sql包中,其中java.sql属于JavaSE,javax.sql属于JavaEE。为了使客户端程序独立于特定的数据库驱动程序,JDBC规范提议开发者使用基于接口的编程情势,即尽量使利用仅正视java.sql及javax.sql中的接口和类。

Java言语访问数据库的一种标准,是一套API

2 JDBC原理

最初SUN集团的禀赋们想编写一套能够接连天下所有数据库的API,不过当他俩刚刚初阶时就发现那是不可完成的职分,因为各类厂商的数据库服务器差别太大了。后来SUN开班与数据库厂商们议论,最终得出的结论是,由SUN提供一套访问数据库的业内(就是一组接口),并提供连接数据库的商事正式,然后挨家挨户数据库厂商会坚守SUN的正经提供一套访问本人公司的数据库服务器的API出现。SUN提供的正统命名为JDBC,而一一厂商提供的,遵守了JDBC规范的,可以访问自个儿数据库的API被称作驱动!

 

JDBC是接口,而JDBC驱动才是接口的兑现,没有驱动无法成功数据库连接!每一个数据库厂商都有和好的驱动,用来延续自身集团的数据库。

本来还有第三方商店特意为某一数据库提供驱动,那样的驱动往往不是开源免费的!

 

        JAVA使用JDBC访问数据库的手续:

JDBC (Java Database Connectivity)
API,即Java数据库编程接口,是一组正式的Java语言中的接口和类,使用这个接口和类,Java客户端程序可以访问各个不相同门类的数据库。比如建立数据库连接、执行SQL语句举办数据的存取操作。

3 JDBC核心类(接口)介绍

JDBC中的宗旨类有:DriverManager、Connection、Statement,和ResultSet!

DriverManger(驱动管理器)的效果有五个:

l  注册驱动:那足以让JDBC知道要采用的是哪个驱动;


获取Connection:若是可以拿走到Connection,那么评释已经与数据库连接上了。

 

Connection对象表示连接,与数据库的简报都以因此那一个目的开展的:

l  Connection最为重大的一个艺术就是用来获取Statement对象;

 

Statement是用来向数据库发送SQL语句的,那样数据库就会履行发送过来的SQL语句:

l  void executeUpdate(String
sql):执行更新操作(insert、update、delete等);

l  ResultSet executeQuery(String
sql):执行查询操作,数据库在执行查询后会把询问结果,查询结果就是ResultSet;

 

ResultSet对象表示查询结果集,唯有在履行查询操作后才会有结果集的发生。结果集是一个二维的表格,有行有列。操作结果集要上学活动ResultSet内部的“行光标”,以及取得当前行上的每一列上的数额:

l  boolean next():使“行光标”移动到下一行,并回到移动后的行是否留存;

l  XXX getXXX(int
col):获取当前行指定列上的值,参数就是列数,列数从1开始,而不是0。

 

        1.到手数据库驱动程序

 

4 Hello JDBC

 

上边初阶编制第二个JDBC程序

4.1 mysql数据库的驱动jar包:mysql-connector-java-5.1.13-bin.jar;

4.2 获取连接

拿到连接必要两步,一是拔取Driver
Manager来注册驱动,二是选用DriverManager来获取Connection对象。

  1. 挂号驱动

看通晓了,注册驱动就唯有一句话:Class.forName(“com.mysql.jdbc.Driver”),上面的故事情节都以对那句代码的分解。未来大家的代码中,与登记驱动相关的代码唯有这一句。

DriverManager类的registerDriver()方法的参数是java.sql.Driver,但java.sql.Driver是一个接口,完结类由mysql驱动来提供,mysql驱动中的java.sql.Driver接口的落实类为com.mysql.jdbc.Driver!那么注册驱动的代码如下:

DriverManager.registerDriver(new com.mysql.jdbc.Driver());

上面代码即使可以登记驱动,但是出现硬编码(代码依赖mysql驱动jar包),即使未来想连接Oracle数据库,那么必要求修改代码的。并且实际这种注册驱动的主意是注册了三回驱动!

JDBC中规定,驱动类在被加载时,要求协调“主动”把团结注册到DriverManger中,上边大家来探视com.mysql.jdbc.Driver类的源代码:(有静态代码块)

com.mysql.jdbc.Driver.java

public class Driver extends NonRegisteringDriver implements java.sql.Driver {

    static {

       try {

           java.sql.DriverManager.registerDriver(new Driver());

       } catch (SQLException E) {

           throw new RuntimeException("Can’t register driver!");

       }

    }

……

}

 

com.mysql.jdbc.Driver类中的static块会制造本类对象,并注册到DriverManager中。那表达只要去加载com.mysql.jdbc.Driver类,那么就会进行这几个static块,从而也就会把com.mysql.jdbc.Driver注册到DriverManager中,所以可以把挂号驱动类的代码修改为加载驱动类

Class.forName(“com.mysql.jdbc.Driver”);

 

  1. 收获连接

得到连接的也唯有一句代码:DriverManager.getConnection(url,username,password),其中username和password是登录数据库的用户名和密码,尽管本人没说错的话,你的mysql数据库的用户名和密码分别是:root、123。

url核查复杂一点,它是用来找到要延续数据库“网址”,就好比你要浏览器中追寻百度时,也亟需提供一个url。上面是mysql的url:

jdbc:mysql://localhost:3306/mydb1

JDBC规定url的格式由三有些组成,各个部分中级使用冒号分隔。

l  第一片段是jdbc,这是固定的;

l  第二有些是数据库名称,那么连接mysql数据库,第二有的当然是mysql了;


第三有些是由数据库厂商规定的,大家必要通晓各类数据库厂商的渴求,mysql的第三局地各自由数据库服务器的IP地址(localhost)、端口号(3306),以及DATABASE名称(mydb1)组成。

  

上面是赢得连接的语句:

Connection con =
DriverManager.getConnection(“jdbc:mysql://localhost:3306/mydb1”,”root”,”123”);

 

还足以在url中提供参数

jdbc:mysql://localhost:3306/mydb1?useUnicode=true&characterEncoding=UTF8

 

useUnicode参数指定那几个一连数据库的历程中,使用的字节集是Unicode字节集;

characherEncoding参数指定穿上接连数据库的经过中,使用的字节集编码为UTF-8编码。请留心,mysql中指定UTF-8编码是交由的是UTF8,而不是UTF-8。要小心了!

 

4.3 获取Statement(createStatement)

在得到Connectoin之后,表达已经与数据库连接上了,上面是透过Connection创造Statement对象的代码:

Statement stmt = con.createStatement();

Statement是用来向数据库发送要实践的SQL语句的!

4.4 发送SQL增、删、改语句(insert  into只会潜移默化一行,delete和update
N行)

997755.com澳门葡京 ,String sql = “insert into user values(’zhangSan’, ’123’)”;

int m = stmt.executeUpdate(sql);

里头int类型的重返值表示执行那条SQL语句所影响的行数,大家领略,对insert来说,最后不得不影响一行,而update和delete只怕会影响0~n行。

假诺SQL语句执行破产,那么executeUpdate()会抛出一个SQLException。

4.5 发送SQL查询语句【ResultSet结果集】

String sql = “select * from user”;

ResultSet rs = stmt.executeQuery(sql);

请留意,执行查询利用的不是executeUpdate()方法,而是executeQuery()方法。executeQuery()方法再次回到的是ResultSet,ResultSet封装了询问结果,大家称为结果集。

4.6 读取结果集中的数目

ResultSet就是一张二维的报表,它里面有一个“行光标”,光标暗中同意的岗位在“第一行上方”,我们得以调用rs对象的next()方法把“行光标”向下活动一行,当第四回调用next()方法时,“行光标”就到了第一行记录的义务,那时就足以采用ResultSet提供的getXXX(int
col)方法来取得指定列的数目了:

rs.next();//光标移动到第一行

rs.getInt(1);//获取第一行第一列的数量

当您利用rs.getInt(1)方法时,你必须可以毫无疑问第1列的数据类型就是int类型,要是您不能够自然,那么最好应用rs.getObject(1)。在ResultSet类中提供了一漫山遍野的getXXX()方法,比较常用的方法有:

Object getObject(int col)

String getString(int col)

int getInt(int col)

double getDouble(int col)

4.7 关闭

与IO流一样,使用后的事物都须求关闭!关闭的逐一是先拿到的后关门,后拿走的先关闭。

rs.close();

stmt.close();

con.close();

 

4.8 代码

 

    public static Connection getConnection() throws Exception {

       Class.forName("com.mysql.jdbc.Driver");

       String url = "jdbc:mysql://localhost:3306/mydb1";

       return DriverManager.getConnection(url, "root", "123");

    }

    @Test

    public void insert() throws Exception {

       Connection con = getConnection();

       Statement stmt = con.createStatement();

       String sql = "insert into user values(‘zhangSan’, ‘123’)";

       stmt.executeUpdate(sql);

       System.out.println("插入成功!");

    }

    @Test

    public void update() throws Exception {

       Connection con = getConnection();

       Statement stmt = con.createStatement();

       String sql = "update user set password=’456′ where username=’zhangSan’";

       stmt.executeUpdate(sql);

       System.out.println("修改成功!");

    }

    @Test

    public void delete() throws Exception {

       Connection con = getConnection();

       Statement stmt = con.createStatement();

       String sql = "delete from user where username=’zhangSan’";

       stmt.executeUpdate(sql);

       System.out.println("删除成功!");

    }

    @Test

    public void query() throws Exception {

       Connection con = getConnection();

       Statement stmt = con.createStatement();

       String sql = "select * from user";

       ResultSet rs = stmt.executeQuery(sql);

       while(rs.next()) {

           String username = rs.getString(1);

           String password = rs.getString(2);

           System.out.println(username + ", " + password);

       }

    }

 

4.9 规范化代码(对于尤其以及资源的处理,用try catch finally)

所谓规范化代码就是不管是还是不是出现分外,都要关闭ResultSet、Statement,以及Connection,借使你还记得IO流的规范化代码,那么下边的代码你就精晓怎么着意思了。

 

    @Test

    public void query() {

       Connection con = null;

       Statement stmt = null;

       ResultSet rs = null;

[c1]     try {

           con = getConnection();[c2] 

           stmt = con.createStatement();

           String sql = "select * from user";

           rs = stmt.executeQuery(sql);

           while(rs.next()) {

              String username = rs.getString(1);

              String password = rs.getString(2);

              System.out.println(username + ", " + password);

           }

       } catch(Exception e) {

           throw new RuntimeException(e);

       } finally {

           try {

              if(rs != null) rs.close();

              if(stmt != null) stmt.close();

              if(con != null) con.close();

        } catch(SQLException e) {}

       }

    }


 

        2.创立数据库连接

  
JDBC规范动用接口和完毕分离的构思设计了Java数据库编程的框架。接口包涵在java.sql及javax.sql包中,其中java.sql属于JavaSE,javax.sql属于JavaEE。这么些接口的兑现类叫做数据库驱动程序,由数据库的厂商或任何的厂商或个体提供。

        3.执行SQL语句

 

        4.收获结果集

   为了使客户端程序独立于特定的数据库驱动程序,JDBC规范提出开发者使用基于接口的编程形式,即尽量使利用仅依赖java.sql及javax.sql中的接口和类。

        5.对结果集做相应的拍卖(增,删,改,查)

997755.com澳门葡京 1

        6.关门资源:那里释放的是DB中的资源

 

       
mysql的驱动包提供了java.sql.Driver这么些SPI的落成,达成类是com.mysql.jdbc.Driver,在mysql-connector-java-5.1.6.jar中,咱们得以看出有一个META-INF/services目录,目录下有一个文本名为java.sql.Driver的文本,其中的内容是com.mysql.jdbc.Driver。
在运行DriverManager.getDriver并传播参数“com.mysql.jdbc.Driver”时,DriverManager会从mysql-connector-java-5.1.6.jar中找到com.mysql.jdbc.Driver并实例化重临一个com.mysql.jdbc.Driver的实例。而SPI(ServiceProvider
Interface)是指部分提需要你继续、伸张,落成自定义成效的类、接口或然措施。

JDBC驱动程序:

997755.com澳门葡京 2

什么样是JDBC驱动程序?

     
 SPI是一种回调的思想,回调是指我们在选拔api时,我们得以向API传入一个类依然措施,API在合适的小运调用类恐怕措施。SPI是在有的通用的正儿八经中,为规范的贯彻产商提供的扩张点。标准在上层提供API,API内部使用了SPI,当API被客户利用时,会动态得从此时此刻运作的classpath中检索该SPI的贯彻,然后使用该SPI的贯彻来成功API的功力。

这几个是各类数据库厂家依照JDBC的专业制作的JDBC完结类

     
 SPI的达成情势是:提供完毕的兑现类打包成Jar文件,这几个Jar文件里面必须有META-INF目录,其下又有services目录,其下有一个文件文件,文件名即为SPI接口的人名,文件的始末该jar包中提供的SPI接口的落成类名。

JDBC驱动程序的三种档次:

       大家看档次中Mybaits的jar包会发现:

1.       第一种档次的驱动程序的贯彻是透过将JDBC的调用全部信托给任何编程接口来兑现的,比如ODBC。那系列型的驱动程序要求设置本地代码库,即借助于当地的顺序,所以便携性较差。比如JDBC-ODBC桥驱动程序

private class SqlSessionInterceptor implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      SqlSession sqlSession = getSqlSession(
          SqlSessionTemplate.this.sqlSessionFactory,
          SqlSessionTemplate.this.executorType,
          SqlSessionTemplate.this.exceptionTranslator);
      try {
        Object result = method.invoke(sqlSession, args);
        if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
          // force commit even on non-dirty sessions because some databases require
          // a commit/rollback before calling close()
          sqlSession.commit(true);
        }
        return result;
      } catch (Throwable t) {
        Throwable unwrapped = unwrapThrowable(t);
        if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
          // release the connection to avoid a deadlock if the translator is no loaded. See issue #22
          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
          sqlSession = null;
          Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
          if (translated != null) {
            unwrapped = translated;
          }
        }
        throw unwrapped;
      } finally {
        if (sqlSession != null) {
          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
        }
      }
    }
  }

2.       第三种档次的驱动程序的完毕是一对基于Java语言的。即该驱动程序一部分是用Java语言编写,其余一些委托本地的数据库的客户端代码来兑现。同类型1的驱动一样,该项目的驱动程序也借助地方的次第,所以便携性较差

     
sqlSessionTemplate.SqlSessionInterceptor源码,有没有一种很熟谙的痛感?至于getConnection自身去看;用过ElasticSearch和Redis的童鞋,细心的童鞋会发现再三再四字符串都龙岩小异,连接都以近似的,标准的接连形式,提升效能,有效控制连接;

3.       第三系列型的驱动程序的落到实处是整套基于JAVA语言的。该品种的驱动程序常常由某个中间件服务器提供,那样客户端程序可以行使数据库非亲非故的商议和中间件服务器举办通讯,中间件服务器再将客户端的JDBC调用转载给数据库举办拍卖

      ElasticSearch的总是字符串:

4.       第七种档次的驱动程序的兑现是所有基于JAVA语言的。该项目标驱动程序中富含了特定数据库的访问协议,使得客户端可以一向和数据库举行通讯

protected SearchResponse getSearchResponse(String fieldName, String indexName) {
    client = null;
    SearchResponse response = null;
    try {
        getClient();
        MaxAggregationBuilder aggregation =
                AggregationBuilders
                        .max("agg")
                        .field(fieldName);
        SearchRequestBuilder request = client.prepareSearch(indexName).addAggregation(aggregation);
        response = request.execute().actionGet();
    } catch (Exception ex) {
        logger.error("getSearchResponse", ex);
    } finally {
        if (client != null) {
            client.close();
        }
        return response;
    }
}

 

     Jedis连接字符串:

JDBC类结构:

执行命令如下:
Jedis jedis = null;
try {
    jedis = jedisPool.getResource();
    //具体的命令
    jedis.executeCommand()
} catch (Exception e) {
    logger.error("op key {} error: " + e.getMessage(), key, e);
} finally {
    //注意这里不是关闭连接,在JedisPool模式下,Jedis会被归还给资源池。
    if (jedis != null) 
        jedis.close(); 
}

                           DriverManager

     
 拦截器的贯彻都以依照代理的设计形式达成的,简而言之就是要创建一个目的类的代理类,在代理类中推行目的类的方式并在点子在此以前实施拦截器代码,拦截器一般有登陆拦截器——验证会话音讯,权限拦截器——验证权限新闻,那么SqlSessionInterceptor是为啥的?

 

     
 Mybatis拦截器设计的一个初衷就是为着供用户在好哪一天候可以已毕本人的逻辑而不必去动Mybatis固有的逻辑。打个假如,对于Executor,Mybatis中有三种达成:BatchExecutor、ReuseExecutor、SimpleExecutor和CachingExecutor。
那一个时候假诺你以为这三种落成对于Executor接口的query方法都不可以满足你的须求,那怎么办呢?是要去改源码吗?当然不。大家得以建立一个Mybatis拦截器用于拦截Executor接口的query方法,在阻止之后已毕协调的query方法逻辑,之后可以选择是或不是继续执行原来的query方法。允许你在已映射语句执行进度中的某一点举行阻拦调用。有的用Mybatis拦截器统封装分页,有的用它完毕读写分离等,借使读写分离依旧提出配置多数据源;

Driver                               Driver

     
 spring整合mybatis之后,通过动态代理的办法,使用SqlSessionTemplate持有的sqlSessionProxy属性来代理执行sql操作,由spring管理的sqlSeesion在sql方法(增删改查等操作)执行完毕后就自动关闭了sqlSession,不须要大家对其进展手动关闭。

 

       愿你有情人终成眷属,愿你有个有趣的灵魂,愿你拍本身一砖!

Connection                         Connection

 

Statement                                  Statement

 

Resultset                                    Resultset

 

DriverManager:这些是一个贯彻类,它是一个工厂类,用来生产Driver对象的

其一类的结构设计情势为工厂方法

Driver:那是驱动程序对象的接口,它指向一个毋庸置疑的数据库驱动程序对象,那么这些数据库驱动程序对象是从哪里来的啊?

DriverManager工厂中有个措施:getDriver(String
URL),通过那几个法子可以得到驱动程序对象,这些法子是在一一数据库厂商按JDBC规范设计的数据库驱动程序包里的类中静态完毕的,也等于在静态块中

Connection:那个接口可以制向一个数据库连接对象,那么怎样赢得那一个延续对象呢?

是通过DriverManager工厂中的getConnection(String URL)方法拿到的

Statement:用于实施静态的SQL语句的接口,通过Connection中的createStatement方法拿到的

Resultset:用于指向结果集对象的接口,结果集对象是透过Statement中的execute等办法赢得的

 

JAVA使用JDBC访问数据库的步调:

1.     拿到数据库驱动程序

2.     创制数据库连接

3.     执行SQL语句

4.     拿到结果集

5.     对结果集做相应的拍卖(增,删,改,查)

6.     关闭资源:那里释放的是DB中的资源

997755.com澳门葡京 3 

  

设置classpath:

1.     在java文件中起的包名一定假诺工程基目录下的子目录,classpath:基目录

2.     .jar包,必要将这一个.jar包的门道概括那一个文件的全名添加到classpath中来

Oracle连天字符串的书写格式:

“oracle:jdbc:thin:@ip:1521: 数据库名”,”数据库用户名”,”数据库密码”

 

简单的例证:

997755.com澳门葡京 4

package moudule1.first;



import java.sql.*;



public class FirstJdbc

{

      public static void main(String[] args)

      {

                 String sql="select * from yuchen_user";

                 Connection con=null;

                 Statement st=null;

                 ResultSet rs=null;



       try

       { 

                 Class.forName("oracle.jdbc.driver.OracleDriver");

                 con=DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:name", "scott","tiger");

                 st=con.createStatement();

                 rs=st.executeQuery(sql);

                 while(rs.next())

                 {

                            System.out.println(rs.getInt("id"));

                            System.out.println(rs.getString("name"));

                 }

       }catch(Exception e)

       {

                 e.printStackTrace();

       }finally

       {

                 try

                 {

                      con.close();

                 }catch(Exception e)

                 {}



                 try

                 {

                      st.close();

                 }catch(Exception e)

                 {

                 }



                 try

                 {

                      rs.close();

                 }catch(Exception e)

                 {

                 }



       }





      }



}

997755.com澳门葡京 5

 

 

常用数据库的驱动程序及JDBC URL:

Oracle数据库:

驱动程序包名:ojdbc14.jar

 驱动类的名字:oracle.jdbc.driver.OracleDriver

 JDBC URL:jdbc:oracle:thin:@dbip:port:databasename

 表明:驱动程序包名有可能会变

       JDBC
URL中森林绿字体部分必须维持原状的保留,为该驱动识其余URL格式。蓝紫字体部分要求基于数据库的设置情状填写。其中各类部分含义如下:

       
dbip –为数据库服务器的IP地址,假如是当地可写:localhost或127.0.0.1。

        port –为数据库的监听端口,需求看安装时的安排,缺省为1521。

        databasename –为数据库的SID,平常为全局数据库的名字。

        举例假使要拜访当地的多寡库allandb,端口1521,那么URL写法如下:

       jdbc:oracle:thin:@localhost:1521:allandb 下载地址如下:

 

SQL Server数据库

   驱动程序包名:msbase.jar mssqlserver.jar msutil.jar

   驱动类的名字:com.microsoft.jdbc.sqlserver.SQLServerDriver

   JDBC
URL:jdbc:microsoft:sqlserver://dbip:port;DatabaseName=databasename

   表达:驱动程序包名有大概会变

        JDBC
URL中玉绿字体部分必须纹丝不动的保留,为该驱动识其他URL格式。稻草黄字体部必要根据数据库的装置景况填写。其中种种部分含义如下:

      
dbip –为数据库服务器的IP地址,假若是本地可写:localhost或127.0.0.1。

        port –为数据库的监听端口,必要看安装时的配备,缺省为1433。

       databasename –数据库的名字。

       举例如若要拜访当地的数量库allandb,端口1433,那么URL写法如下:

       jdbc: microsoft: sqlserver:@localhost:1433; DatabaseName =allandb

       下载地址:

 

 MySQL数据库

   驱动程序包名:mysql-connector-java-3.1.11-bin.jar

   驱动类的名字:com.mysql.jdbc.Driver

   JDBC URL:jdbc:mysql://dbip:port/databasename

   表明:驱动程序包名有恐怕会变

        JDBC
URL中茶青字体部分必须维持原状的保留,为该驱动识其余URL格式。本白字体部须要依照数据库的装置情况填写。其中各样部分含义如下:

       
dbip –为数据库服务器的IP地址,如果是本土可写:localhost或127.0.0.1。

        port –为数据库的监听端口,须求看安装时的安排,缺省为3306。

        databasename –数据库的名字。

        举例如果要拜访当地的多寡库allandb,端口1433,那么URL写法如下:

       jdbc:mysql://localhost:3306/allandb

   下载地址:

 

Access数据库

   驱动程序包名:该驱动程序蕴含在JavaSE中,不必要分外安装。

   驱动类的名字:sun.jdbc.odbc.JdbcOdbcDriver

   JDBC URL:jdbc:odbc:datasourcename

   表明:该驱动只好工作在Windows系统中,首先要求在操作系统中树立一个方可访问Access数据库的本土数据源(ODBC),即使名字为allandb,那么URL写法如下:

        jdbc:odbc:allandb

 

PreparedStatement接口:

预编译的sql语句对象

效用: 消除了书写sql语句时有些非正规的字符与sql保留字符争持的难题,非凡便于

997755.com澳门葡京 6

/**

*知识点:

*PreparedStatement接口及方法的使用

*程序目标:

*java文件:

*PreparedInsert.java:连接数据库,插入一条数据

*JdbcUtil.java:实现一个工具类,功能:1.连接数据库 2.关闭资源

*/



package moudule1.preparedstatement;



import java.sql.*;

import moudule1.com.*;



public class PreparedInsert

{

      public static void main(String[] args)

      {

           String sql="insert into yuchen_user (id,name) values (?,?)";

           System.out.println(sql);



           Connection con=null;

           PreparedStatement ps=null;



           try{

                 con=JdbcUtil.getConnection();

                 ps=con.prepareStatement(sql);



                 ps.setInt(1,2);

                 ps.setString(2,"zhangsan");

                 ps.executeUpdate();



                 ps.setInt(1,3);

                 ps.setString(2,"lisi");

                 ps.executeUpdate();



           }catch(Exception e){

                 e.printStackTrace();

           }finally{

                 JdbcUtil.close(con,ps);

                 }

           }

      }

997755.com澳门葡京 7

 

 

997755.com澳门葡京 8

package moudule1.com;



import java.sql.*;



public class JdbcUtil{



      public static Connection getConnection() throws Exception{

           Class.forName("oracle.jdbc.driver.OracleDriver");

       return DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:name", "scott","tiger");

           }



      public static void close(Connection con,Statement st){



           close(con);

           close(st);



           }



      public static void close(Connection con,Statement st,ResultSet rs){





           close(con,st);

           close(rs);



           }



      public static void close(Connection con){

           try{



                 con.close();



           }catch(Exception e){





                 }



           }



      public static void close(Statement st){



           try{



                 st.close();



           }catch(Exception e){



                 }

           }



      public static void close(ResultSet rs){



           try{



                 rs.close();



           }catch(Exception e){



                 }



           }



      }

997755.com澳门葡京 9

 

数据库的增删改查的例子:

997755.com澳门葡京 10

/**

*知识点:

*JDBC+SQL+ORACLE

*程序目标:

*UserDao.java:实现了数据库的增删改查

*JdbcUtil.java:工具类,有连库和关闭资源的方法

*/



package moudule1.idus;



import java.sql.*;

import moudule1.com.*;



public class UserDao{



      private String sql;

      private Connection con;

      private Statement st;

      private ResultSet rs;



      public UserDao(){

           sql=null;

           con=null;

           st=null;

           rs=null;

           }



      public void insert(){



           sql="insert into yuchen_user (id,name) values(";

           sql+="4,'zhouwu')";

           System.out.println(sql);



           try{



           con=JdbcUtil.getConnection();

           st=con.createStatement();

           st.executeUpdate(sql);



           }catch(Exception e){



                 e.printStackTrace();



           }finally{



                 JdbcUtil.close(con,st);



                 }



           }





      public void delete(){



           sql="delete from yuchen_user where id=2";

           System.out.println(sql);



           try{



                 con=JdbcUtil.getConnection();

            st=con.createStatement();

            st.executeUpdate(sql);



           }catch(Exception e){



                 e.printStackTrace();



           }finally{



                 JdbcUtil.close(con,st);



                 }

           }





      public void update(){



           sql="update yuchen_user set name='liumang' where id=1";

           System.out.println(sql);



           try{



                 con=JdbcUtil.getConnection();

            st=con.createStatement();

            st.executeUpdate(sql);



           }catch(Exception e){



                 e.printStackTrace();



           }finally{



                 JdbcUtil.close(con,st);



                 }

           }





      public void select(){



           sql="select * from yuchen_user";

           System.out.println(sql);



           try{



                 con=JdbcUtil.getConnection();

            st=con.createStatement();

             rs=st.executeQuery(sql);



            while(rs.next()){



               System.out.println(rs.getInt(1));

               System.out.println(rs.getString(2));



               }



           }catch(Exception e){



                 e.printStackTrace();



           }finally{



                 JdbcUtil.close(con,st,rs);



                 }



           }





      public static void main(String[] args){



           UserDao ud=new UserDao();

           ud.select();

           ud.insert();

           ud.select();

           ud.update();

           ud.select();

           ud.delete();

           ud.select();

           }

      }

997755.com澳门葡京 11

 

有的常用的主意:

997755.com澳门葡京 12

/**

*知识点:

*execute方法,getResultSet(),getUpdateCount()

*程序目标:

*JdbcUtil.java:工具类,连接数据库,关闭资源

*sqlExecutor.java:命令行参数输入sql语句,并执行该语句

*/

package moudule1.fangfa;



import java.sql.*;

import moudule1.com.*;



public class sqlExecutor{



      public static void main(String[] args){



           Connection con=null;

           Statement st=null;



           try{



                 con=JdbcUtil.getConnection();

                 st=con.createStatement();

                 boolean str=st.execute(args[0]);



                 if(str){



                      ResultSet rs=st.getResultSet();



                      while(rs.next()){

                            System.out.println(rs.getInt("id")+":"+rs.getString("name"));

                            }



                            rs.close();



                 }else{

                      int row=st.getUpdateCount();

                      System.out.println(row);

                      }



           }catch(Exception e){



                 e.printStackTrace();



           }finally{



                 JdbcUtil.close(con,st);



                 }

           }

      }

997755.com澳门葡京 13

 

  1. 补充
      JDBC连接MySQL

加载及注册JDBC驱动程序

Class.forName(“com.mysql.jdbc.Driver”);

Class.forName(“com.mysql.jdbc.Driver”).newInstance();

JDBC URL 定义驱动程序与数据源之间的连年

业内语法:

<protocol(首要通信协议)>:<subprotocol(次要通信协议,即驱动程序名称)>:<data source identifier(数据源)>

MySQL的JDBC URL格式:

jdbc:mysql//[hostname][:port]/[dbname][?param1=value1][&param2=value2]….

 

示例:jdbc:mysql://localhost:3306/sample_db?user=root&password=your_password

 

大面积参数:

user                       用户名

password                  密码

autoReconnect                  联机退步,是否再次联合(true/false)

maxReconnect              尝试重新联合次数

initialTimeout               尝试再一次联合间隔

maxRows                   传回最大行数

useUnicode                 是或不是选择Unicode字体编码(true/false)

characterEncoding          何种编码(GB2312/UTF-8/…)

relaxAutocommit            是不是自动提交(true/false)

capitalizeTypeNames        数据定义的名目以大写表示

确立连接对象

String
url=”jdbc:mysql://localhost:3306/sample_db?user=root&password=your_password”;

Connection con = DriverManager.getConnection(url);

创建SQL陈述式对象(Statement Object)

Statement stmt =
con.createStatement();

执行SQL语句

executeQuery()

String query = “select * from test”;

ResultSet rs=stmt.executeQuery(query);

结果集ResultSet

while(rs.next())

{rs.getString(1);rs.getInt(2);}

executeUpdate()

String upd=”insert into test (id,name) values(1001,xuzhaori)”;

int con=stmt.executeUpdate(upd);

execute()

示例:

try{
}

catch(SQLException sqle)

{

}

finally

{

}

 

Java类型和SQL类型 技术手册P421

PreparedStatement(预编语句)

PreparedStatement stmt = conn.prepareStatement(“insert into
test(id,name)values(?,?)”);

stmt.setInt(1,id);

stmt.setString(2,name);

注:一旦设定语句的参数值后,就可以屡屡举办改语句,直到调用clearParameters()方法将他排除截止

CallableStatement(预储程序)技术手册P430

JDBC2.0使用

ResultSet对象中的光标上下自由运动

Statement stmt = con.createStatement (ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_READ_ONLY);

ResultSet rs=stmt.executeQuery(“select * from test”);

 

public Statement createStatement(int resultSetType,int
resultSetConcuttency) throws SQLException

 

resultSetType

TYPE_FORWARD_ONLY            只好利用next()方法。

TYPE_SCROLL_SENSITIVE        可以上下移动,可以拿到改变后的值。

TYPE_SCROLL_INSENSITIVE      可以上下移动。

resultSetConcuttency

CONCUR_READ_ONLY        只读

CONCUR_UPDATABLE        ResultSet对象足以实施数据库的剧增、修改、和移除

 

直接运用ResultSet对象执行更新数据

增产多少

997755.com澳门葡京 14

Statement stmt=con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_PUDATABLE);

ResultSet uprs=stmt.executeQuery("select * from test");

uprs.moveToInsertRow();

uprs.updateInt(1,1001);

uprs.updateString(2,"许召日");

uprs.insertRow;

997755.com澳门葡京 15

 

更新数据

997755.com澳门葡京 16

Statement stmt=con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_PUDATABLE);

ResultSet uprs=stmt.executeQuery("select * from test");

uprs.last();

uprs.updateString("name","xuzhaori");

uprs.updateRow;

997755.com澳门葡京 17

 

除去数据

997755.com澳门葡京 18

Statement stmt=con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_PUDATABLE);

ResultSet uprs=stmt.executeQuery("select * from test");

uprs.absolute(4);

uprs.deleteRow();

997755.com澳门葡京 19

 

 

批处理

con.setAutoCommit(false);  关闭自动确认方式

Statement stmt=con.createStatement();

int[] rows;

stmt.addBatch(“insert into test values(1001,xuzhaori)”);

stmt.addBatch(“insert into test values(1002,xuyalin)”);

rows=stmt.executeBatch();

con.commit();  没有任何不当,执行批处理stmt.executeBatch();

 

JNDI-数据源(Data Source)与连接池(Connection Pool)

Tomcat的JDBC数据源设置  技术手册P439

连接池工具-Proxool Var
0.8.3 技术手册P446

设置web.xml

997755.com澳门葡京 20

<?xml version="1.0" encoding="ISO-8859-1"?>

<!--<?xml version="1.0" encoding="GB2312"?>-->



<web-app xmlns="http://java.sun.com/xml/ns/j2ee"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"

version="2.4">

….

<servlet>

<servlet-name>ServletConfigurator</servlet-name>

<servlet-class>org.logicalcobwebs.proxool.configuration.ServletConfigurator</servlet-class>



<init-param>

<param-name>propertyFile</param-name>

<param-value>WEB-INF/classes/Proxool.properties</param-value>

</init-param>

<load-on-startup>1</load-on-startup>

</servlet>

997755.com澳门葡京 21

 

后端计算端口添加下列

997755.com澳门葡京 22

<servlet>

<servlet-name>Admin</servlet-name>

<servlet-class>org.logicalcobwebs.proxool.admin.servlet.AdminServlet</servlet-class>

</servlet>



<servlet-mapping>

<servlet-name>Admin</servlet-name>

<url-pattern>/Admin</url-pattern>

</servlet-mapping>



….



</web-app>

997755.com澳门葡京 23

 

配置Proxool.properties

997755.com澳门葡京 24

jdbc-0.proxool.alias=JSPBook

jdbc-0.proxool.driver-class=com.mysql.jdbc.Driver

jdbc-0.proxool.driver-url=jdbc:mysql://localhost:3306/sample_db?user=root&password=browser&useUnicode=true&characterEncoding=UTF-8

jdbc-0.proxool.maximum-connection-count=10

jdbc-0.proxool.prototype-count=4

jdbc-0.proxool.house-keeping-test-sql=select CURRENT_DATE

jdbc-0.proxool.verbose=true

jdbc-0.proxool.statistics=10s,1m,1d    后端统计接口添加此行

jdbc-0.proxool.statistics-log-level=DEBUG

997755.com澳门葡京 25

 

使用Proxool连接池

997755.com澳门葡京 26

Connection con = DriverManager.getConnection("proxool.JSPBook");

Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);

String query = "SELECT * FROM employee";

ResultSet rs = stmt.executeQuery(query);

997755.com澳门葡京 27

 

 

 

 

使用JDBC时,大家都会很当然得利用下列语句:

 

Class.forName("com.mysql.jdbc.Driver");        
String url = "jdbc:mysql://127.0.0.1/test?useUnicode=true&characterEncoding=utf-8";        
String user = "";        
String psw = "";        
Connection con = DriverManager.getConnection(url,user,psw);      

 

 

 

   
为啥说很自然吧,因为无论网上如故书本教程上得例子都以这般的,而且程序也真正正常运行了,于是我们也就心安理得的找葫芦画瓢下去了。

    一定要有这一句吗?不是的,我们完全可以用那样一句代替它:

 

 

 

997755.com澳门葡京 28

com.mysql.jdbc.Driver driver = new com.mysql.jdbc.Driver();        
//or:        
//new com.mysql.jdbc.Driver();        
String url = "jdbc:mysql://127.0.0.1/test?useUnicode=true&characterEncoding=utf-8";        
String user = "";        
String psw = "";        
Connection con = DriverManager.getConnection(url,user,psw);       

997755.com澳门葡京 29

 

       
大家莫不都看看个大体来了,大家只需求在调用DriverManager的getConnection方法以前,保险相应的Driver类已经被加载到jvm中,并且完成了类的起初化工作就行了,而具体是什么完成这些效应却是没有讲究的。

    谈到类的初叶化,这里不得不提,在如何的景况下类才可以开头化?

 

 

  1. 成立类的实例
  2. 做客某个类或接口的静态变量,大概对该静态变量赋值
  3. 调用类的静态方法
  4. 反射(如Class.forName(“com.lang.String”)
  5. 初步化一个类的子类
  6.  Java虚拟机启动时被标为启动类的类

   
下面二种办法都得以兑现这些作用,因而先后可以正常运作。注意了,如果咱们举办如下操作,程序是不或然健康运作的,因为如此只是使Driver类被装载到jvm中,却从不展开对应的先导化工作。具体有关类的加载和早先化详细,可以翻阅小编的这篇博文《JVM虚拟机和类加载器》。

 

com.mysql.jdbc.Driver driver = null;        
//or:        
ClassLoader cl = new ClassLoader();        
cl.loadClass("com.mysql.jdbc.Driver");      

 

 

       
 我们都精晓JDBC是运用Bridge模式进行设计的,DriverManager就是其中的Abstraction,java.sql.Driver是Implementor,com.mysql.jdbc.Driver是Implementor的一个切实落实(请参见GOF的Bridge形式的讲述)。大家瞩目了,前一个Driver是一个接口,后者却是一个类,它完成了面前的Driver接口。

       
 Bridge情势中,Abstraction(DriverManager)是要具有一个Implementor(Driver)的引用的,可是大家在选拔进程中,并没有将Driver对象注册到DriverManager中去呀,那是怎么回事呢?jdk文档对Driver的叙说中有那般一句:

       
When a Driver class is loaded, it should create an instance of itself and register it with the DriverManager 

       
哦,原来是com.mysql.jdbc.Driver在装载完后活动帮我们成功了这一步骤。源代码是那样的:

 

 

    可以看来DriveManager里面定义了静态方法,而mysql等驱动类都以其中用静态数据块的章程来开始化,达成Driver对象注册到DriverManager中,所以若是jvm装载了那么些使得类就会将Driver对象注册到DriverManager中去(Class.forName(xxx.xx.xx) 重回的是一个类;Class.forName(xxx.xx.xx);的出力是须求JVM查找并加载指定的类,约等于说JVM会执行该类的静态代码段 。静态代码是和class绑定的,class装载成功就代表执行了您的静态代码了。而且今后不会再走那段静态代码了。),前面就足以平昔利用了。

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website