jdbc

# jdbc

![image-20201215145708863](jdbc.assets/image-20201215145708863.png)

## 数据的持久化

简单来讲:数据持久化,即就是将数据(内存对象)保存到可以长时间保存的设备(磁盘)的过程。

数据持久化就是让数据在 “持久状态” 和 “瞬间状态” 相互转换的一种机制(例如:IO 操作,JDBC 操作)。

- 持久状态:系统或应用重启之后数据(内存对象)的状态依然存在。

- 瞬间状态:系统或应用在工作时可操作的状态

## 获取数据库连接

## 类加载时机

- 创建类的实例,也就是new一个对象

- 访问某个类或接口的静态变量,或者对该静态变量赋值

- 调用类的静态方法

- 反射(Class.forName("com.lyj.load"))

- 初始化一个类的子类(会首先初始化子类的父类)

- JVM启动时标明的启动类,即文件名和类名相同的那个类 

  **除此之外,下面几种情形需要特别指出:**

  对于一个final类型的静态变量,如果该变量的值在编译时就可以确定下来,那么这个变量相当于“宏变量”。Java编译器会在编译时直接把这个变量出现的地方替换成它的值,因此即使程序使用该静态变量,也不会导致该类的初始化。反之,如果final类型的静态Field的值不能在编译时确定下来,则必须等到运行时才可以确定该变量的值,如果通过该类来访问它的静态变量,则会导致该类被初始化。

### Driver(驱动)接口实现

#### 加载和注册DBUtils驱动

第一次主动使用Class类,就会加载到内存中

### SPI

SPI全称为(Service Provider Interface) ,是JDK内置的一种服务提供发现机制;主要被框架的开发人员使用,**比如java.sql.Driver接口**,数据库厂商实现此接口即可,当然要想让系统知道具体实现类的存在,还需要使用固定的存放规则,需要**在classpath下的META-INF/services/目录里创建一个以服务接口命名的文件,这个文件里的内容就是这个接口的具体的实现类**

### URL(统一资源定位器)

```properties

url=jdbc:mysql://127.0.0.1:3306/job?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai

```

URL 是统一资源定位符(Uniform Resource Locator)的简称,它表示 Internet 上某一资源的地址。通过 URL 用户可以访问各种网络资源,比如常见的 WWW 以及 FTP 站点。浏览器可以通过解析给定的 URL 在网络上查找相应的文件或其他资源。

## 加载驱动

因为这里只讨论jdbc,所以通过反射来获取驱动。

```java

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

```

## 创建连接,调用DriverManager.getConnection方法,返回一个连接对象Connection

```java

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

```

> url是指你的数据库地址,jdbc:mysql://(这里写你服务器的ip地址)/(这里写你的服务名)

> 服务器ip地址若是本机的话就是127.0.0.1:3306(其中3306是mysql的默认端口号)

> user就是你的数据库用户名,同理passwrd就是你的数据库密码

### Java连接MySQL数据库

```Java

public void test1() throws Exception{

        String url = "jdbc:mysql://127.0.0.1:3306/job?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai";

        String user = "root";

        String password = "root";

        String driverName = "com.mysql.cj.jdbc.Driver";

        //实例化Driver

        Class clazz = Class.forName(driverName);

        Driver driver = (Driver) clazz.newInstance();

        //注册驱动

        DriverManager.registerDriver(driver);

        //获取连接

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

        System.out.println(conn);

    }

```

### java创建配置文件连接

```Java

@Test

    public void test3() throws Exception{

        Properties properties = new Properties();

        properties.load(JdbcTest.class.getClassLoader().getResourceAsStream("1.properties"));

        String url = properties.getProperty("url");

        System.out.println(url);

        String username = properties.getProperty("mysql.username");

        System.out.println(username);

        String password = properties.getProperty("mysql.password");

        //实例化Driver

        //注册驱动

        //获取连接

        Connection conn = DriverManager.getConnection(url,username,password);

        System.out.println(conn);

    }

```

配置文件

```properties

url=jdbc:mysql://127.0.0.1:3306/job?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai

mysql.username=rootpo

mysql.password=root

mysql.dirvername=com.mysql.cj.jdbc.Driver

```

## 执行sql语句

### 创建sql命令发送器

```java

  Statement stat = conn.createStatement();

1

  当然也可以创建PreparedStatement对象

  String sql = "你的sql语句"

  PreparedStatement prep = conn.prepareStatement(sql语句);

  PreparedStatement的效率比 Statement好些,还能使用预编译

```

### 执行sql命令

#### 查询语句,然后返回结果

```java

@Test

    public void testStatement2() {

        List courses = new ArrayList<>();

        Connection connection = null;

        Statement statement = null;

        ResultSet resultSet = null;

        try {

            String sql = "select * from user";

            connection = jdbcUtil.getConnection();

            statement = connection.createStatement();

            resultSet = statement.executeQuery(sql);

            while (resultSet.next()) {

                Integer id = resultSet.getInt("id");

                String username = resultSet.getString("username");

                Integer password = resultSet.getInt("password");

                courses.add(new Course(id,username,password));

            }

        }catch (SQLException e){

            e.getErrorCode();

        }finally {

            jdbcUtil.closeAll(connection,statement,resultSet);

        }

        System.out.println(courses);

    }

------------------------------------------------------------------------------------------------------

public static void closeAll(Connection connection, Statement statement, ResultSet resultSet){

        if (connection != null){

            try {

                connection.close();

            } catch (SQLException throwables) {

                throwables.printStackTrace();

            }

        }

        if (statement != null){

            try {

                statement.close();

            } catch (SQLException throwables) {

                throwables.printStackTrace();

            }

        }

        if (resultSet != null){

            try {

                resultSet.close();

            } catch (SQLException throwables) {

                throwables.printStackTrace();

            }

        }

    }

```

#### 插入语句,然后返回结果

```java

int i = stmt.executeUpdate("insert into 表名 values(id,'字段1','字段2')");

//处理结果

if (i > 0) {

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

} else {

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

}

```

#### 修改语句,然后返回结果

```java

int i = stmt.executeUpdate("update 表名 set 字段1='xx1',字段2='xx2' where id=xxx");

// 处理结果

if (i > 0) {

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

} else {

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

}

```

#### 删除语句,然后返回结果

```java

int i = stmt.executeUpdate("delete from 表名 where id=xxx");

// 处理结果

if (i > 0) {

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

} else {

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

}

```

## 关闭资源

```java

//若创建了结果集ResultSet,也需要关闭

rs.close();

stmt.close();

conn.close();

```

### **JDBC常用类**

  **资源关闭:ResultSet,Statement,Connection的顺序执行close;**

####  DriverManager类:

管理一组 JDBC 驱动程序的基本服务;Driver的子类;

方法:**static Connection **getConnection**(String url, String user, String password);//返回Connection接口;

- String url="jdbc:mysql://localhost:3306/test";

- String url="jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&setCharacterEncoding=utf8";

- 屏蔽SSL的警告; 解决乱码;

- String url="jdbc:mysql:///test?useSSL=false&serverTimezone=UTC";//8.0新版本;

####  Connection接口:

    **方法:**

- Statement **createStatement**();//创建一个 Statement 对象来将 SQL 语句发送到数据库。

- **Prepared****Statement** **prepare****Statement**(String **sql**);

- 创建一个 PreparedStatement 对象来将**参数化的 SQL** 语句发送到数据库。

- close();

#### Statement接口:

用于执行静态 SQL 语句并返回它所生成结果的对象。

**方法:**

- int executeUpdate(String sql);//执行**DDL**和**DML**语句;DML返回影响的行数;DDL返回0;

- ResultSet executeQuery(String sql);//执行**DQL**语句;返回 ResultSet结果集;

- close();

```Java

public class Test {

    public static void main(String[] args) throws Exception {

        //  1、加载驱动

        //把com.mysql.jdbc.Driver这份字节码加载进JVM

        //当一份字节码被加载到JVMs时,就会执行该字节码中的静态代码块

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

        // 2、创建连接

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

        String user = "root";

        String password = "000000";

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

        // 3、创建sql

        String sql = "select * from user where name = ?";

        PreparedStatement prepareStatement = conn.prepareStatement(sql);

        prepareStatement.setString(1, "ls");

        // 4、执行sql

        ResultSet resultSet = prepareStatement.executeQuery();

        // 5、处理返回结果

        while (resultSet.next()) {

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

        }

        // 6、关闭资源

        prepareStatement.close();

        conn.close();

    }

}

```

### SQL注入:

#####  sql注入:

    正常代码:sid:001  ----> delete from student where sid = "001";

    问题代码:sid:999 or 1=1  -----> delete from student where sid = "999" or 1=1;

      //delete from student;等于删除整表;

    解决后代码:sid:999 or 1=1  -----> delete from student where sid = "999 or 1=1";

解决办法:PreparedStatement;Statement的子接口;

```Java

public static boolean login(String username,String password){

        List courses = new ArrayList<>();

        Connection connection = null;

        Statement statement = null;

        ResultSet resultSet = null;

        try {

            String sql = "select id,username,password from user where username='" + username

                    +"'and password='" + password +"'";

            connection = jdbcUtil.getConnection();

            statement = connection.createStatement();

            resultSet = statement.executeQuery(sql);

            return resultSet.next();

        }catch (SQLException e){

            e.getErrorCode();

        }finally {

            jdbcUtil.closeAll(connection,statement,resultSet);

        }

        return false;

    }

public static void main(String[] args) {

    boolean login = login("1","334' or '1' = '1");

    System.out.println(login);

}

```

### prepared Statement的使用

- 可以通过调用 Connection 对象的 **prepareStatement(String sql)** 方法获取 PreparedStatement 对象

- **PreparedStatement 接口是 Statement 的子接口,它表示一条预编译过的 SQL 语句**

- PreparedStatement 对象所代表的 SQL 语句中的参数用问号(?)来表示(?在SQL中表示占位符),调用 PreparedStatement 对象的 setXxx() 方法来设置这些参数. setXxx() 方法有两个参数,第一个参数是要设置的 SQL 语句中的参数的索引(从 1 开始),第二个是设置的 SQL 语句中的参数的值

![img](jdbc.assets/20201121213156938.png)

#### 和Statement的对比

- 代码的可读性和可维护性。

- PreparedStatement 能最大可能提高性能:

  - DBServer会对**预编译**语句提供性能优化。因为预编译语句有可能被重复调用,所以语句在被DBServer的编译器编译后的执行代码被缓存下来,那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中就会得到执行。

  - 在statement语句中,即使是相同操作但因为数据内容不一样,所以整个语句本身不能匹配,没有缓存语句的意义.事实是没有数据库会对普通语句编译后的执行代码缓存。这样每执行一次都要对传入的语句编译一次。

  - (语法检查,语义检查,翻译成二进制命令,缓存)

- PreparedStatement 可以防止 SQL 注入

#### 插入案例

**PreparedStatement常用的方法:**

void setObject(int parameterIndex, Object x, int targetSqlType)

![在这里插入图片描述](jdbc.assets/20201121225840166.png)

**parameterIndex** the first parameter is 1, the second is 2, …占位符参数索引是从1开始的

其余也是如此:

> void setInt(int parameterIndex, int x)

> void setLong(int parameterIndex, long x)

> void setString(int parameterIndex, String x)

> void setBlob (int parameterIndex, Blob x)

> void setDate(int parameterIndex, java.sql.Date x, Calendar cal)

![在这里插入图片描述](jdbc.assets/20201121225713195.png)

```Java

@Test

    public void getConnection(){

        Connection connection = null;

        PreparedStatement preparedStatement = null;

        try{

            //加载配置文件

            InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("1.properties");

            Properties pr = new Properties();

            pr.load(is);

            //读取配置信息

            String user = pr.getProperty("mysql.username");

            String password = pr.getProperty("mysql.password");

            String url = pr.getProperty("url");

            String dirvername = pr.getProperty("mysql.dirvername");

            //加载驱动

            Class.forName(dirvername);

            //获取连接

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

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

            //预编译sql语句,得到PreparedStatement对象

            preparedStatement = connection.prepareStatement(sql);

            //填充占位符

            preparedStatement.setString(1,"123456");

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

            Date date = new Date();

            preparedStatement.setDate(2,new java.sql.Date(date.getTime()));

            //执行操作

            preparedStatement.execute();

        }catch (Exception e){

            e.printStackTrace();

        }finally {

            if (preparedStatement != null){

                try {

                    preparedStatement.close();

                } catch (SQLException throwables) {

                    throwables.printStackTrace();

                }

            }

        }

    }

```

## 读取XML文件

```Java

public class XmlTest {

    public static void main(String[] args) {

        readXml();

    }

    public static Clazz readXml(){

        Clazz clazz = new Clazz();

        SAXReader reader = new SAXReader();

        try{

            Document document = reader.read(Test.class.getClassLoader().getResourceAsStream("jdbc.xml"));

            Element root = document.getRootElement();

            clazz.setName(root.attribute("name").getValue());

            List elements = root.elements();

            for (Element element : elements) {

                System.out.println(element.getName() + "---" + element.getData());

            }

        }catch (DocumentException e){

            e.getCause();

        }

        return clazz;

    }

}

```

XML文件:

```properties

    root

    root

    jdbc:mysql://127.0.0.1:3306/job?useUnicode=true characterEncoding=utf8 serverTimezone=Asia/Shanghai

    com.mysql.cj.jdbc.Driver

```

你可能感兴趣的:(jdbc)