• JDBC


    1.jdbc概述

    问题:实际开发中,不可能用工具或者命令行操作数据库,数据库表中的数据最终要使用Java程序来操作,那么Java中如何操作数据库中的数据呢?

    Java语言中,有一个专门连接数据库的规范(JDBC),专门负责连接数据库进行数据操作的规范

    JDBC只是SUN编写的一堆接口(规范的体现),SUN公司自己并没有实现

     

    问题 为什么SUN只定义一个JDBC规范,而不实现呢?

    因为市面上的数据库很多,每个数据库内部接口不会向外暴露,而且即便是暴露让SUN去实现,市面上很多数据库全部要SUN来实现不现实

     

    实际中哪个数据库需要支持JAVA语言,就需要自己实现JavaJDBC规范,因为实现了JDBC很多接口,那么就会有很多实现类,而很多实现类在java中会使用一个专门的包封装起来,叫做jar(在JDBC中叫做驱动包),各大数据库产商实现JDBC规范以后都会把他们jar包放在官网上以供开发者下载使用

    DBC(Java DataBase Connectivity):是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基

     JDBC规范对应的api

     

    2. 入门案例

    1)连接数据库

    案例使用JDBC操作MySQL数据库

    2)创建普通java项目

    3)在项目下面新建一个lib目录

    4) MySQL驱动包拷贝到项目中并添加依赖

     

    5) 获取数据库连接对象

     准备:

    1.拷贝MySQL的驱动包到项目中去:mysql-connector-java-5.1.x-bin.jar

    2.build path,告速项目去哪里去找字节码文件.

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

    操作JDBC的第一步,获取JDBC的连接对象.:Connection.

    步骤:

      1.加载注册驱动.

        就是把驱动中的Driver字节码加载到JVM.

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

       为什么这句话就可以加载注册驱动?

       第一步:com.mysql.jdbc.Driver.class这份字节码加载到JVM.

       第二步:当一份字节码被加载进JVM,马上就会执行该字节码中的静态代码块.

        第三步:该静态代码中,就在完成,先创建驱动对象,再注册.

      2.通过DriverManager获取连接对象.

        public static Connection getConnection(String url,String user,String password)

    Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/dbName","root","admin");

    jdbc:mysql://localhost:3306/dbName

    jdbc:mysql:// :连接MySQL数据库的协议,不同数据库协议不一样

    localhost:3306 :数据库软件的主机和端口

    dbName : 具体要连接数据库

        若数据库安装在本机,并且端口是默认的3306,则可以简写:

        Connection conn = DriverManager.getConnection("jdbc:mysql:///dbName","root","admin");

    验证已经获取连接:可以在MySQL控制台,使用命令:show processlist; 查看MySQL运行进程.

     

     1 public class GetConnectionDemo {
     2 
     3 public static void main(String[] args) throws Exception {
     4 
     5  
     6 
     7 //1.加载注册驱动 : 把当前类对应的字节码加载到JVM中
     8 
     9 Class.forName("com.mysql.jdbc.Driver");
    10 
    11 //2.获取数据库连接
    12 
    13 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
    14 
    15 System.out.println(conn);
    16 
    17  
    18 
    19 }
    20 
    21 }

    3.创建表-DDL操作

    在其他操作之间先要把数据库表要创建出来

    创建一张t_student:

    id:

    name:

    age:

     1 /*
     2 
     3  *
     4 
     5  * 创建表操作
     6 
     7  * SQL : create table t_student (id int primary key auto_increment,name varchar(50),age int)
     8 
     9  */
    10 
    11  
    12 
    13 public static void main(String[] args) throws Exception {
    14 
    15 String sql = "create table t_student (id int primary key auto_increment,name varchar(50),age int)";
    16 
    17 //贾琏欲执事
    18 
    19 //1,加载注册驱动
    20 
    21 Class.forName("com.mysql.jdbc.Driver");
    22 
    23 //2,获取数据库连接
    24 
    25 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
    26 
    27 //3,创建语句对象(用于执行SQL语句的对象)
    28 
    29 Statement st = conn.createStatement();
    30 
    31 //4, 执行SQL语句
    32 
    33 //int rows = st.executeUpdate(String sql);执行DDL和DML语句,放回的是受影响的行数
    34 
    35 //ResultSet res = st.executeQuery(String sql);执行DQL查询语句,返回的结果集对象
    36 
    37 st.executeUpdate(sql);
    38 
    39 //5,释放资源(先开后关)
    40 
    41 st.close();
    42 
    43 conn.close();
    44 
    45 }

     

    4. DML操作-表数据的增删改

      1 //DML : 对表数据的增删改操作
      2 
      3 public class DMLDemo {
      4 
      5  
      6 
      7 /*
      8 
      9  * 向 t_student表中插入一条数据
     10 
     11  * sql : insert into t_student(name,age) values ('乔峰',30)
     12 
     13  */
     14 
     15 @Test
     16 
     17 public void testInsert() throws Exception {
     18 
     19 String sql = "insert into t_student(name,age) values ('乔峰',30)";
     20 
     21  
     22 
     23 // 1.加载注册驱动
     24 
     25 Class.forName("com.mysql.jdbc.Driver");
     26 
     27  
     28 
     29 // 2.获取数据库连接对象
     30 
     31 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
     32 
     33 // 3.创建语句对象
     34 
     35 Statement st = conn.createStatement();
     36 
     37  
     38 
     39 // 4.执行SQL语句
     40 
     41 // int rows = st.executeUpdate(String sql);执行DDL和DML语句,放回的是受影响的行数
     42 
     43 // ResultSet res = st.executeQuery(String sql);执行DQL查询语句,返回的结果集对象
     44 
     45 int rows = st.executeUpdate(sql);
     46 
     47 System.out.println(rows);
     48 
     49 //5.释放资源(先开后关)
     50 
     51 st.close();
     52 
     53 conn.close();
     54 
     55  
     56 
     57 }
     58 
     59 /*
     60 
     61  * 删除操作: 删除t_student表中的某一条数据
     62 
     63  * SQL :delete from t_student where id = 2
     64 
     65  */
     66 
     67 @Test
     68 
     69 public void testDelete() throws Exception {
     70 
     71 String sql = "delete from t_student where id = 2";
     72 
     73  
     74 
     75 // 1.加载注册驱动
     76 
     77 Class.forName("com.mysql.jdbc.Driver");
     78 
     79  
     80 
     81 // 2.获取数据库连接对象
     82 
     83 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
     84 
     85 // 3.创建语句对象
     86 
     87 Statement st = conn.createStatement();
     88 
     89  
     90 
     91 // 4.执行SQL语句
     92 
     93 // int rows = st.executeUpdate(String sql);执行DDL和DML语句,放回的是受影响的行数
     94 
     95 // ResultSet res = st.executeQuery(String sql);执行DQL查询语句,返回的结果集对象
     96 
     97 int rows = st.executeUpdate(sql);
     98 
     99 System.out.println(rows);
    100 
    101 //5.释放资源(先开后关)
    102 
    103 st.close();
    104 
    105 conn.close();
    106 
    107 }
    108 
    109 /*
    110 
    111  * 修改操作 : 修改t_student表中的某一条数据
    112 
    113  * SQL : update t_student set name = '虚竹',age = 50 where id = 3
    114 
    115  */
    116 
    117 @Test
    118 
    119 public void testUpdate() throws Exception {
    120 
    121 String sql = "update t_student set name = '虚竹',age = 50 where id = 3";
    122 
    123  
    124 
    125 // 1.加载注册驱动
    126 
    127 Class.forName("com.mysql.jdbc.Driver");
    128 
    129  
    130 
    131 // 2.获取数据库连接对象
    132 
    133 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
    134 
    135 // 3.创建语句对象
    136 
    137 Statement st = conn.createStatement();
    138 
    139  
    140 
    141 // 4.执行SQL语句
    142 
    143 // int rows = st.executeUpdate(String sql);执行DDL和DML语句,放回的是受影响的行数
    144 
    145 // ResultSet res = st.executeQuery(String sql);执行DQL查询语句,返回的结果集对象
    146 
    147 int rows = st.executeUpdate(sql);
    148 
    149 System.out.println(rows);
    150 
    151 //5.释放资源(先开后关)
    152 
    153 st.close();
    154 
    155 conn.close();
    156 
    157 }
    158 
    159 }

     5.DQL操作-查询操作

    1) 查询操作的分析

    2)查询具体操作

    结果集的列的位置

     

    使用 rs.next() 偏移光标,循环指定具体的某一行

    获取数据的具体方法

     Object

    getObject(int columnIndex) 
     columnIndex : 通过结果集的位置(1开始)获取对应的数据

     Object

    getObject(String columnLabel) 
    columnLabel : 通过结果集的 列名获取对应的数据

     

      1 package cn.sxt.jdbc._01connection;
      2 
      3  
      4 
      5  
      6 
      7 import java.sql.Connection;
      8 
      9 import java.sql.DriverManager;
     10 
     11 import java.sql.ResultSet;
     12 
     13 import java.sql.Statement;
     14 
     15 import java.util.ArrayList;
     16 
     17 import java.util.List;
     18 
     19  
     20 
     21 import org.junit.Test;
     22 
     23  
     24 
     25 //DQL :查询操作
     26 
     27 public class D_DQLDemo {
     28 
     29  
     30 
     31 /*
     32 
     33  * 多行查询 :查询t_student表中的所有数据
     34 
     35  * SQL : select * from t_student
     36 
     37  */
     38 
     39 @Test
     40 
     41 public void testList() throws Exception {
     42 
     43 String sql = "select * from t_student";
     44 
     45  
     46 
     47 // 1.加载注册驱动
     48 
     49 Class.forName("com.mysql.jdbc.Driver");
     50 
     51  
     52 
     53 // 2.获取数据库连接对象
     54 
     55 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
     56 
     57 // 3.创建语句对象
     58 
     59 Statement st = conn.createStatement();
     60 
     61  
     62 
     63 // 4.执行SQL语句
     64 
     65 // int rows = st.executeUpdate(String sql);执行DDL和DML语句,放回的是受影响的行数
     66 
     67 // ResultSet res = st.executeQuery(String sql);执行DQL查询语句,返回的结果集对象
     68 
     69 ResultSet rs = st.executeQuery(sql);
     70 
     71  
     72 
     73  
     74 
     75 //创建list集合用于封装Student对象
     76 
     77 List<Student> stus = new ArrayList<>();
     78 
     79  
     80 
     81 while(rs.next()) {
     82 
     83 //1.通过结果集的位置获取对应的数
     84 
     85 /*Object id = rs.getObject(1);
     86 
     87 Object name = rs.getObject(2);
     88 
     89 Object age = rs.getObject(3);*/
     90 
     91  
     92 
     93 //2.通过结果集的 列名获取对应的数据
     94 
     95 /*Object id = rs.getObject("id");
     96 
     97 Object name = rs.getObject("name");
     98 
     99 Object age = rs.getObject("age");*/
    100 
    101 //3.通过数据库数据和Java对应的数据类型获取对应的只
    102 
    103 int id = rs.getInt("id");
    104 
    105 String name = rs.getString("name");
    106 
    107 int age = rs.getInt("age");
    108 
    109 //System.out.println(id+","+name+","+age);
    110 
    111  
    112 
    113 //将获取的数据封装成对应的Student对象
    114 
    115 Student stu = new  Student(id, name, age);
    116 
    117  
    118 
    119 //将一个个Student对象添加到list集合中
    120 
    121 stus.add(stu);
    122 
    123 }
    124 
    125  
    126 
    127 for (Student student : stus) {
    128 
    129 System.out.println(student);
    130 
    131 }
    132 
    133 //5.释放资源(先开后关)
    134 
    135 rs.close();
    136 
    137 st.close();
    138 
    139 conn.close();
    140 
    141 }
    142 
    143  
    144 
    145  
    146 
    147 /*
    148 
    149  * 单行查询: 查询出t_student 指定id的信息
    150 
    151  * SQL : select * from t_student where id = 1;
    152 
    153  */
    154 
    155 @Test
    156 
    157 public void testGetOne() throws Exception {
    158 
    159 String sql = "select * from t_student where id = 2";
    160 
    161  
    162 
    163 // 1.加载注册驱动
    164 
    165 Class.forName("com.mysql.jdbc.Driver");
    166 
    167  
    168 
    169 // 2.获取数据库连接对象
    170 
    171 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
    172 
    173 // 3.创建语句对象
    174 
    175 Statement st = conn.createStatement();
    176 
    177  
    178 
    179 // 4.执行SQL语句
    180 
    181 // int rows = st.executeUpdate(String sql);执行DDL和DML语句,放回的是受影响的行数
    182 
    183 // ResultSet res = st.executeQuery(String sql);执行DQL查询语句,返回的结果集对象
    184 
    185 ResultSet rs = st.executeQuery(sql);
    186 
    187  
    188 
    189 if(rs.next()) {
    190 
    191 //1.通过结果集的位置获取对应的数
    192 
    193 /*Object id = rs.getObject(1);
    194 
    195 Object name = rs.getObject(2);
    196 
    197 Object age = rs.getObject(3);*/
    198 
    199  
    200 
    201 //2.通过结果集的 列名获取对应的数据
    202 
    203 /*Object id = rs.getObject("id");
    204 
    205 Object name = rs.getObject("name");
    206 
    207 Object age = rs.getObject("age");*/
    208 
    209 //3.通过数据库数据和Java对应的数据类型获取对应的只
    210 
    211 int id = rs.getInt("id");
    212 
    213 String name = rs.getString("name");
    214 
    215 int age = rs.getInt("age");
    216 
    217 //System.out.println(id+","+name+","+age);
    218 
    219  
    220 
    221 //将获取的数据封装成对应的Student对象
    222 
    223 Student stu = new  Student(id, name, age);
    224 
    225 System.out.println(stu);
    226 
    227 }
    228 
    229 //5.释放资源(先开后关)
    230 
    231 rs.close();
    232 
    233 st.close();
    234 
    235 conn.close();
    236 
    237 }
    238 
    239 }

     

    6.预编译语句对象PreparedStatment

    问题 我们有了Statment对象可以执行SQL,为什么还要使用PreparedStatment

    优势

    1. SQL语句结构清晰,参数的设置和SQL语句分离

    2. 性能更高

    3. 防止SQL注入

    Statement: 表示静态SQL语句对象.

    PreparedStatement:Statement的子接口,表示预编译SQL语句对象. 通过占位符(?)来拼SQL.  

    1) 创建PreparedStatement

    创建语句对象 Statment

     Statement

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

     

    创建预编译语句对象PreparedStatement

     PreparedStatement

    prepareStatement(String sql) 
    创建预编译语句对象,SQL是带有占位符的SQL模板.

     

    2)执行SQL语句的方法

    [1] Statment

    在执行SQL语句的时候回带上SQL语句

     ResultSet

    executeQuery(String sql) 
              执行给定的 SQL 语句,该语句返回单个 ResultSet 对象。

     int

    executeUpdate(String sql) 
              执行给定 SQL 语句,该语句可能为 INSERTUPDATE 或 DELETE 语句,或者不返回任何内容的 SQL 语句(如 SQL DDL 语句)。

    [2]PreparedStatement 

    在执行SQL语句的方法中不需要设置SQL语句

     ResultSet

    executeQuery() 
              在此 PreparedStatement 对象中执行 SQL 查询,并返回该查询生成的 ResultSet 对象。

     int

    executeUpdate() 
              在此 PreparedStatement 对象中执行 SQL 语句,该语句必须是一个 SQL 数据操作语言(Data Manipulation Language,DML)语句,比如 INSERTUPDATE 或 DELETE 语句;或者是无返回内容的 SQL 语句,比如 DDL 语句。

    3) 设置站位参数的值

    void  setXxx(int parameterIndex,Xxx value):用于设置占位符参数,

           parameterIndex:第几个问号. 注意:1开始.

           value:设置的真实值.

    Xxx:表示数据类型.String/int/long/Double

     

    4)代码

      1 package cn.sxt.jdbc._01connection;
      2 
      3  
      4 
      5 import static org.junit.Assert.*;
      6 
      7  
      8 
      9 import java.sql.Connection;
     10 
     11 import java.sql.DriverManager;
     12 
     13 import java.sql.PreparedStatement;
     14 
     15  
     16 
     17 import org.junit.Test;
     18 
     19  
     20 
     21 //DML : 对表数据的增删改操作,使用预编译语句对象
     22 
     23 public class E_DMLByPreparedStatmentDemo {
     24 
     25  
     26 
     27 /*
     28 
     29  * 向 t_student表中插入一条数据
     30 
     31  * sql : insert into t_student(name,age) values ('乔峰',30)
     32 
     33  */
     34 
     35 @Test
     36 
     37 public void testInsert() throws Exception {
     38 
     39 String sql = "insert into t_student(name,age) values (?,?)";
     40 
     41  
     42 
     43 // 1.加载注册驱动
     44 
     45 Class.forName("com.mysql.jdbc.Driver");
     46 
     47  
     48 
     49 // 2.获取数据库连接对象
     50 
     51 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
     52 
     53 // 3.创建预编译语句对象
     54 
     55 PreparedStatement ps = conn.prepareStatement(sql);
     56 
     57 //3.1设置占位符参数
     58 
     59 ps.setString(1, "东方姑娘");
     60 
     61 ps.setInt(2, 18);
     62 
     63  
     64 
     65 // 4.执行SQL语句:注意不要带SQL参数
     66 
     67 ps.executeUpdate();
     68 
     69 //5.释放资源(先开后关)
     70 
     71 ps.close();
     72 
     73 conn.close();
     74 
     75  
     76 
     77 }
     78 
     79 /*
     80 
     81  * 删除操作: 删除t_student表中的某一条数据
     82 
     83  * SQL :delete from t_student where id = 2
     84 
     85  */
     86 
     87 @Test
     88 
     89 public void testDelete() throws Exception {
     90 
     91 String sql = "delete from t_student where id = ?";
     92 
     93  
     94 
     95 // 1.加载注册驱动
     96 
     97 Class.forName("com.mysql.jdbc.Driver");
     98 
     99  
    100 
    101 // 2.获取数据库连接对象
    102 
    103 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
    104 
    105 // 3.创建预编译语句对象
    106 
    107 PreparedStatement ps = conn.prepareStatement(sql);
    108 
    109 //3.1设置占位符对应的参数值
    110 
    111 ps.setInt(1, 1);
    112 
    113  
    114 
    115 // 4.执行SQL语句
    116 
    117 int rows = ps.executeUpdate();
    118 
    119 System.out.println(rows);
    120 
    121 //5.释放资源(先开后关)
    122 
    123 ps.close();
    124 
    125 conn.close();
    126 
    127 }
    128 
    129 /*
    130 
    131  * 修改操作 : 修改t_student表中的某一条数据
    132 
    133  * SQL : update t_student set name = '虚竹',age = 50 where id = 3
    134 
    135  */
    136 
    137 @Test
    138 
    139 public void testUpdate() throws Exception {
    140 
    141 String sql = "update t_student set name = ?,age = ? where id = ?";
    142 
    143  
    144 
    145 // 1.加载注册驱动
    146 
    147 Class.forName("com.mysql.jdbc.Driver");
    148 
    149  
    150 
    151 // 2.获取数据库连接对象
    152 
    153 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
    154 
    155 // 3.创建预编译语句对象
    156 
    157 PreparedStatement ps = conn.prepareStatement(sql);
    158 
    159 //3.1设置占位符参数对应的值
    160 
    161 ps.setString(1, "西方失败");
    162 
    163 ps.setInt(2, 40);
    164 
    165 ps.setInt(3, 4);
    166 
    167 // 4.执行SQL语句
    168 
    169 int rows = ps.executeUpdate();
    170 
    171 System.out.println(rows);
    172 
    173 //5.释放资源(先开后关)
    174 
    175 ps.close();
    176 
    177 conn.close();
    178 
    179 }
    180 
    181 }
    182 
    183  

    7. JavaWeb开发的分层设计-三层架构

    1) DAO层设计

    实际开发中,JavaWeb开发代码一般分为三层,分层结构是JavaWeb开发中的一种设计思想,这样会让我们开发层次分明,每一层只要完成对应的功能即可,使得项目便于开发和维护

    【1】Web/表现层 : 主要接受前台浏览器用户的参数,给浏览器响应数据等等

    【2】Service/业务成/服务层:主要处理业务功能,日志,权限,事物,等等

    【3】DAO/持久层 :专门负责和数据库交互,数据处理相关代码

    DAO Data Access Object 数据访问对象

    实际开发中 用户请求到-Web--->Service-->DAO

     2) DAO思想

    3) 使用DAO以后代码的以及包的设计结构

    开发中如果使用的分层,编写的包和类名接口名等等都是有固定规则,不能随便瞎写

    [1]. DAO层接口包命名

    公司域名倒写+项目名称/模块名称+dao

    如 : cn.sxt.crm.dao

    [2]DAO层实现类包命名

    公司域名倒写+项目名称/模块名称+dao+impl

    如 : cn.sxt.crm.dao.impl

    [3] DAO层操作对应表的接口命名

    对应表的名称 + Dao/DAO

    如 : StudentDao/DAO , TeacherDao/DAO

    [4] DAO层操作对应表的实现类命名

    对应表的名称 + Dao/DAOImpl

    如 : StudentDaoImpl/DAOImpl , TeacherDaoImpl/DAOImpl

    [5]数据表对应的Javadomain/pojo包命名

    POJOPlain Ordinary Java Object)简单的Java对象
    domian : 域对象

    公司域名倒写+项目名称/模块名称+domain/pojo

    如 : cn.sxt.crm.domain

    [6] 对应的测试包命名

    公司域名倒写+项目名称/模块名称+test

    如 : cn.sxt.crm.test

    [7]项目的工具类包命名

    公司域名倒写+项目名称/模块名称+util/utils

    如 : cn.sxt.crm.util/utils

    [8]DAO代码设计结构

    [9] Dao的实现类代码

      1 package cn.sxt.jdbc.dao.impl;
      2 
      3  
      4 
      5 import java.sql.Connection;
      6 
      7 import java.sql.DriverManager;
      8 
      9 import java.sql.PreparedStatement;
     10 
     11 import java.sql.ResultSet;
     12 
     13 import java.sql.SQLException;
     14 
     15 import java.util.ArrayList;
     16 
     17 import java.util.List;
     18 
     19  
     20 
     21 import cn.sxt.jdbc.dao.StudentDao;
     22 
     23 import cn.sxt.jdbc.domain.Student;
     24 
     25  
     26 
     27 public class StudentDaoImpl implements StudentDao {
     28 
     29  
     30 
     31 @Override
     32 
     33 public int saveStudent(Student stu) {
     34 
     35 String sql = "insert into t_student(name,age) values (?,?)";
     36 
     37  
     38 
     39 Connection conn = null;
     40 
     41 PreparedStatement ps = null;
     42 
     43 try {
     44 
     45  
     46 
     47 // 1.加载注册驱动
     48 
     49 Class.forName("com.mysql.jdbc.Driver");
     50 
     51  
     52 
     53 // 2.获取数据库连接对象
     54 
     55 conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
     56 
     57 // 3.创建预编译语句对象
     58 
     59 ps = conn.prepareStatement(sql);
     60 
     61 //3.1设置占位符参数
     62 
     63 ps.setString(1, stu.getName());
     64 
     65 ps.setInt(2, stu.getAge());
     66 
     67  
     68 
     69 // 4.执行SQL语句:注意不要带SQL参数
     70 
     71 return ps.executeUpdate();
     72 
     73  
     74 
     75  
     76 
     77 } catch (Exception e) {
     78 
     79 e.printStackTrace();
     80 
     81 }finally {
     82 
     83 //5.释放资源(先开后关)
     84 
     85 try {
     86 
     87 if(ps !=null) {
     88 
     89 ps.close();
     90 
     91 }
     92 
     93 } catch (SQLException e) {
     94 
     95 e.printStackTrace();
     96 
     97 }finally {
     98 
     99 try {
    100 
    101 if(conn !=null) {
    102 
    103 conn.close();
    104 
    105 }
    106 
    107 } catch (SQLException e) {
    108 
    109 // TODO Auto-generated catch block
    110 
    111 e.printStackTrace();
    112 
    113 }
    114 
    115 }
    116 
    117 }
    118 
    119 return 0;
    120 
    121 }
    122 
    123  
    124 
    125 @Override
    126 
    127 public int deleteById(int id) {
    128 
    129  
    130 
    131 String sql = "delete from t_student where id = ?";
    132 
    133  
    134 
    135 Connection conn = null;
    136 
    137 PreparedStatement ps = null;
    138 
    139 try {
    140 
    141  
    142 
    143 // 1.加载注册驱动
    144 
    145 Class.forName("com.mysql.jdbc.Driver");
    146 
    147  
    148 
    149 // 2.获取数据库连接对象
    150 
    151 conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
    152 
    153 // 3.创建预编译语句对象
    154 
    155 ps = conn.prepareStatement(sql);
    156 
    157 //3.1设置占位符参数
    158 
    159 ps.setInt(1, id);
    160 
    161  
    162 
    163 // 4.执行SQL语句:注意不要带SQL参数
    164 
    165 return ps.executeUpdate();
    166 
    167  
    168 
    169  
    170 
    171 } catch (Exception e) {
    172 
    173 e.printStackTrace();
    174 
    175 }finally {
    176 
    177 //5.释放资源(先开后关)
    178 
    179 try {
    180 
    181 if(ps !=null) {
    182 
    183 ps.close();
    184 
    185 }
    186 
    187 } catch (SQLException e) {
    188 
    189 e.printStackTrace();
    190 
    191 }finally {
    192 
    193 try {
    194 
    195 if(conn !=null) {
    196 
    197 conn.close();
    198 
    199 }
    200 
    201 } catch (SQLException e) {
    202 
    203 // TODO Auto-generated catch block
    204 
    205 e.printStackTrace();
    206 
    207 }
    208 
    209 }
    210 
    211 }
    212 
    213 return 0;
    214 
    215 }
    216 
    217  
    218 
    219 @Override
    220 
    221 public int updateStudentById(Student stu) {
    222 
    223  
    224 
    225 String sql = "update t_student set name = ?,age = ? where id = ?";
    226 
    227  
    228 
    229 Connection conn = null;
    230 
    231 PreparedStatement ps = null;
    232 
    233 try {
    234 
    235  
    236 
    237 // 1.加载注册驱动
    238 
    239 Class.forName("com.mysql.jdbc.Driver");
    240 
    241  
    242 
    243 // 2.获取数据库连接对象
    244 
    245 conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
    246 
    247 // 3.创建预编译语句对象
    248 
    249 ps = conn.prepareStatement(sql);
    250 
    251 //3.1设置占位符参数
    252 
    253 ps.setString(1, stu.getName());
    254 
    255 ps.setInt(2, stu.getAge());
    256 
    257 ps.setInt(3, stu.getId());
    258 
    259 // 4.执行SQL语句:注意不要带SQL参数
    260 
    261 return ps.executeUpdate();
    262 
    263  
    264 
    265  
    266 
    267 } catch (Exception e) {
    268 
    269 e.printStackTrace();
    270 
    271 }finally {
    272 
    273 //5.释放资源(先开后关)
    274 
    275 try {
    276 
    277 if(ps !=null) {
    278 
    279 ps.close();
    280 
    281 }
    282 
    283 } catch (SQLException e) {
    284 
    285 e.printStackTrace();
    286 
    287 }finally {
    288 
    289 try {
    290 
    291 if(conn !=null) {
    292 
    293 conn.close();
    294 
    295 }
    296 
    297 } catch (SQLException e) {
    298 
    299 // TODO Auto-generated catch block
    300 
    301 e.printStackTrace();
    302 
    303 }
    304 
    305 }
    306 
    307 }
    308 
    309 return 0;
    310 
    311 }
    312 
    313  
    314 
    315 @Override
    316 
    317 public Student selectById(int id) {
    318 
    319 String sql = "select * from t_student where id = ?";
    320 
    321  
    322 
    323 Connection conn = null;
    324 
    325 PreparedStatement ps = null;
    326 
    327 ResultSet rs = null;
    328 
    329  
    330 
    331 try {
    332 
    333 // 1.加载注册驱动
    334 
    335 Class.forName("com.mysql.jdbc.Driver");
    336 
    337  
    338 
    339 // 2.获取数据库连接对象
    340 
    341 conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
    342 
    343 // 3.创建语句对象
    344 
    345 ps = conn.prepareStatement(sql);
    346 
    347 //3.1设置占位符参数对应的值
    348 
    349 ps.setInt(1, id);
    350 
    351  
    352 
    353 // 4.执行SQL语句
    354 
    355 rs = ps.executeQuery();
    356 
    357 if(rs.next()) {
    358 
    359 //通过数据库数据和Java对应的数据类型获取对应的只
    360 
    361 String name = rs.getString("name");
    362 
    363 int age = rs.getInt("age");
    364 
    365 //System.out.println(id+","+name+","+age);
    366 
    367  
    368 
    369 //将获取的数据封装成对应的Student对象
    370 
    371 Student stu = new  Student(id, name, age);
    372 
    373  
    374 
    375 return stu;
    376 
    377 }
    378 
    379  
    380 
    381 } catch (Exception e) {
    382 
    383 // TODO: handle exception
    384 
    385 }finally {
    386 
    387 try {
    388 
    389 if(rs !=null) {
    390 
    391 rs.close();
    392 
    393 }
    394 
    395 } catch (SQLException e) {
    396 
    397 e.printStackTrace();
    398 
    399 }finally {
    400 
    401 try {
    402 
    403 if(ps !=null) {
    404 
    405 ps.close();
    406 
    407 }
    408 
    409 } catch (SQLException e) {
    410 
    411 e.printStackTrace();
    412 
    413 }finally {
    414 
    415 try {
    416 
    417 if(conn !=null) {
    418 
    419 conn.close();
    420 
    421 }
    422 
    423 } catch (SQLException e) {
    424 
    425 e.printStackTrace();
    426 
    427 }
    428 
    429 }
    430 
    431 }
    432 
    433 }
    434 
    435  
    436 
    437 return null;
    438 
    439 }
    440 
    441  
    442 
    443 @Override
    444 
    445 public List<Student> selectList() {
    446 
    447 String sql = "select * from t_student";
    448 
    449 //创建list集合用于封装Student对象
    450 
    451 List<Student> stus = new ArrayList<>();
    452 
    453  
    454 
    455 Connection conn = null;
    456 
    457 PreparedStatement ps = null;
    458 
    459 ResultSet rs = null;
    460 
    461  
    462 
    463 try {
    464 
    465  
    466 
    467 // 1.加载注册驱动
    468 
    469 Class.forName("com.mysql.jdbc.Driver");
    470 
    471  
    472 
    473 // 2.获取数据库连接对象
    474 
    475 conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
    476 
    477 // 3.创建语句对象
    478 
    479 ps = conn.prepareStatement(sql);
    480 
    481  
    482 
    483 // 4.执行SQL语句
    484 
    485 rs = ps.executeQuery();
    486 
    487 while(rs.next()) {
    488 
    489 //通过数据库数据和Java对应的数据类型获取对应的只
    490 
    491 int id = rs.getInt("id");
    492 
    493 String name = rs.getString("name");
    494 
    495 int age = rs.getInt("age");
    496 
    497 //System.out.println(id+","+name+","+age);
    498 
    499  
    500 
    501 //将获取的数据封装成对应的Student对象
    502 
    503 Student stu = new  Student(id, name, age);
    504 
    505 //将一个个Student对象添加到list集合中
    506 
    507 stus.add(stu);
    508 
    509 }
    510 
    511  
    512 
    513 } catch (Exception e) {
    514 
    515 // TODO: handle exception
    516 
    517 }finally {
    518 
    519 try {
    520 
    521 if(rs !=null) {
    522 
    523 rs.close();
    524 
    525 }
    526 
    527 } catch (SQLException e) {
    528 
    529 e.printStackTrace();
    530 
    531 }finally {
    532 
    533 try {
    534 
    535 if(ps !=null) {
    536 
    537 ps.close();
    538 
    539 }
    540 
    541 } catch (SQLException e) {
    542 
    543 e.printStackTrace();
    544 
    545 }finally {
    546 
    547 try {
    548 
    549 if(conn !=null) {
    550 
    551 conn.close();
    552 
    553 }
    554 
    555 } catch (SQLException e) {
    556 
    557 e.printStackTrace();
    558 
    559 }
    560 
    561 }
    562 
    563 }
    564 
    565 }
    566 
    567  
    568 
    569 return stus;
    570 
    571 }
    572 
    573  
    574 
    575 }
    576 
    577  

    [10] 快速生成单元测试类

    一个dao层或者service编写代码以后,需要为每一个功能都进行单元测试,一个dao中的方法很多。我们快速为这个dao层的类生成单元测试类,(dao的每一个方法都自动生成一个测试方法)

    4) 代码初步重构

    上述的DAO方法中的代码,存在的问题:

    问题1:每个DAO方法中都会写:驱动名称/url/账号/密码,不利于维护.

        解决方案: 声明为成员变量即可.(在被类中任何地方都可以访问)

    问题2:问题1的解决方案有问题.

        每个DAO实现类里都有一模一样的4行代码,不利于维护(考虑有100个DAO实现类,就得重复99次).

        解决方案: 把驱动名称/url/账号/密码这四行代码,专门抽取到一个JDBC的工具类中.---->JdbcUtil.

    问题3:其实DAO方法,每次操作都只想需要Connection对象即可,而不关心是如何创建的.

        解决方案:把创建Connection的代码,抽取到JdbcUtil中,并提供方法getConn用于向调用者返回Connection对象即可.

    问题4:每次调用者调用getConn方法的时候,都会创建一个Connection对象.

          但是,每次都会加载注册驱动一次.--->没必要的.

          解决方案:把加载注册驱动的代码放在静态代码块中--->只会在所在类被加载进JVM的时候,执行一次.

    问题5:每个DAO方法都要关闭资源.(鸡肋代码).

          解决方案:把关闭资源的代码,抽取到JdbcUtil中.

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

          调用者:

            DML:  JdbcUtil.close(conn,st,null);

            DQL:  JdbcUtil.close(conn,st,rs);

    问题6 :连接数据库的账号密码写死在JdbcUtil工具类中了,不利于维护

         抽取 db.properties 配置文件,将数据库对应的账号密码写到配置文件中,然后使用程序读取配置文件内容即可

    [1]JdbcUtil工具类

      1 package cn.sxt.jdbc.util;
      2 
      3  
      4 
      5 import java.io.InputStream;
      6 
      7 import java.sql.Connection;
      8 
      9 import java.sql.DriverManager;
     10 
     11 import java.sql.PreparedStatement;
     12 
     13 import java.sql.ResultSet;
     14 
     15 import java.sql.SQLException;
     16 
     17 import java.util.Properties;
     18 
     19  
     20 
     21  
     22 
     23 public class JdbcUtil {
     24 
     25  
     26 
     27 // alt+shif+a 多行修改,修改以后还原 alt+shif+a
     28 
     29  
     30 
     31 /*private static String driverClassName = "com.mysql.jdbc.Driver";
     32 
     33 private static String url = "jdbc:mysql://localhost:3306/jdbcdemo";
     34 
     35 private static String username = "root";
     36 
     37 private static String password = "root";*/
     38 
     39  
     40 
     41 private static Properties p = new Properties();
     42 
     43  
     44 
     45 static {
     46 
     47 try {
     48 
     49 //1.获取类加载器
     50 
     51 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
     52 
     53 //2,使用类加载器获取项目 类路径下面的文件
     54 
     55 InputStream inputStream = classLoader.getResourceAsStream("db.properties");
     56 
     57  
     58 
     59 //3.使用Priperties加载配置文件对应的输入流
     60 
     61 p.load(inputStream);
     62 
     63  
     64 
     65 Class.forName(p.getProperty("driverClassName"));
     66 
     67 } catch (Exception e) {
     68 
     69 e.printStackTrace();
     70 
     71 }
     72 
     73 }
     74 
     75  
     76 
     77 public static Connection getConnection() {
     78 
     79 try {
     80 
     81  
     82 
     83 return DriverManager.getConnection(p.getProperty("url"), p.getProperty("username"), p.getProperty("password"));
     84 
     85 } catch (Exception e) {
     86 
     87 e.printStackTrace();
     88 
     89 throw new RuntimeException("亲,连接数据库失败", e);
     90 
     91 }
     92 
     93 }
     94 
     95  
     96 
     97 public static void close(Connection conn,PreparedStatement ps,ResultSet rs) {
     98 
     99 try {
    100 
    101 if(rs !=null) {
    102 
    103 rs.close();
    104 
    105 }
    106 
    107 } catch (SQLException e) {
    108 
    109 e.printStackTrace();
    110 
    111 }finally {
    112 
    113 try {
    114 
    115 if(ps !=null) {
    116 
    117 ps.close();
    118 
    119 }
    120 
    121 } catch (SQLException e) {
    122 
    123 e.printStackTrace();
    124 
    125 }finally {
    126 
    127 try {
    128 
    129 if(conn !=null) {
    130 
    131 conn.close();
    132 
    133 }
    134 
    135 } catch (SQLException e) {
    136 
    137 e.printStackTrace();
    138 
    139 }
    140 
    141 }
    142 
    143 }
    144 
    145 }
    146 
    147 }

    [2]使用工具类以后的DAO实现类效果

      1 package cn.sxt.jdbc.dao.impl;
      2 
      3  
      4 
      5 import java.sql.Connection;
      6 
      7 import java.sql.PreparedStatement;
      8 
      9 import java.sql.ResultSet;
     10 
     11 import java.sql.SQLException;
     12 
     13 import java.util.ArrayList;
     14 
     15 import java.util.List;
     16 
     17  
     18 
     19 import cn.sxt.jdbc.dao.StudentDao;
     20 
     21 import cn.sxt.jdbc.domain.Student;
     22 
     23 import cn.sxt.jdbc.util.JdbcUtil;
     24 
     25  
     26 
     27 public class StudentDaoImpl implements StudentDao {
     28 
     29  
     30 
     31  
     32 
     33  
     34 
     35 @Override
     36 
     37 public int saveStudent(Student stu) {
     38 
     39 String sql = "insert into t_student(name,age) values (?,?)";
     40 
     41  
     42 
     43 Connection conn = null;
     44 
     45 PreparedStatement ps = null;
     46 
     47 try {
     48 
     49 conn = JdbcUtil.getConnection();
     50 
     51  
     52 
     53 // 3.创建预编译语句对象
     54 
     55 ps = conn.prepareStatement(sql);
     56 
     57 //3.1设置占位符参数
     58 
     59 ps.setString(1, stu.getName());
     60 
     61 ps.setInt(2, stu.getAge());
     62 
     63  
     64 
     65 // 4.执行SQL语句:注意不要带SQL参数
     66 
     67 return ps.executeUpdate();
     68 
     69  
     70 
     71 } catch (Exception e) {
     72 
     73 e.printStackTrace();
     74 
     75 }finally {
     76 
     77 JdbcUtil.close(conn, ps, null);
     78 
     79 }
     80 
     81 return 0;
     82 
     83 }
     84 
     85  
     86 
     87 @Override
     88 
     89 public int deleteById(int id) {
     90 
     91  
     92 
     93 String sql = "delete from t_student where id = ?";
     94 
     95  
     96 
     97 Connection conn = null;
     98 
     99 PreparedStatement ps = null;
    100 
    101 try {
    102 
    103  
    104 
    105 conn = JdbcUtil.getConnection();
    106 
    107 // 3.创建预编译语句对象
    108 
    109 ps = conn.prepareStatement(sql);
    110 
    111 //3.1设置占位符参数
    112 
    113 ps.setInt(1, id);
    114 
    115  
    116 
    117 // 4.执行SQL语句:注意不要带SQL参数
    118 
    119 return ps.executeUpdate();
    120 
    121  
    122 
    123  
    124 
    125 } catch (Exception e) {
    126 
    127 e.printStackTrace();
    128 
    129 }finally {
    130 
    131 JdbcUtil.close(conn, ps, null);
    132 
    133 }
    134 
    135 return 0;
    136 
    137 }
    138 
    139  
    140 
    141 @Override
    142 
    143 public int updateStudentById(Student stu) {
    144 
    145  
    146 
    147 String sql = "update t_student set name = ?,age = ? where id = ?";
    148 
    149  
    150 
    151 Connection conn = null;
    152 
    153 PreparedStatement ps = null;
    154 
    155 try {
    156 
    157  
    158 
    159 conn = JdbcUtil.getConnection();
    160 
    161 // 3.创建预编译语句对象
    162 
    163 ps = conn.prepareStatement(sql);
    164 
    165 //3.1设置占位符参数
    166 
    167 ps.setString(1, stu.getName());
    168 
    169 ps.setInt(2, stu.getAge());
    170 
    171 ps.setInt(3, stu.getId());
    172 
    173 // 4.执行SQL语句:注意不要带SQL参数
    174 
    175 return ps.executeUpdate();
    176 
    177  
    178 
    179  
    180 
    181 } catch (Exception e) {
    182 
    183 e.printStackTrace();
    184 
    185 }finally {
    186 
    187 JdbcUtil.close(conn, ps, null);
    188 
    189 }
    190 
    191 return 0;
    192 
    193 }
    194 
    195  
    196 
    197 @Override
    198 
    199 public Student selectById(int id) {
    200 
    201 String sql = "select * from t_student where id = ?";
    202 
    203  
    204 
    205 Connection conn = null;
    206 
    207 PreparedStatement ps = null;
    208 
    209 ResultSet rs = null;
    210 
    211  
    212 
    213 try {
    214 
    215 conn = JdbcUtil.getConnection();
    216 
    217 // 3.创建语句对象
    218 
    219 ps = conn.prepareStatement(sql);
    220 
    221 //3.1设置占位符参数对应的值
    222 
    223 ps.setInt(1, id);
    224 
    225  
    226 
    227 // 4.执行SQL语句
    228 
    229 rs = ps.executeQuery();
    230 
    231 if(rs.next()) {
    232 
    233 //通过数据库数据和Java对应的数据类型获取对应的只
    234 
    235 String name = rs.getString("name");
    236 
    237 int age = rs.getInt("age");
    238 
    239 //System.out.println(id+","+name+","+age);
    240 
    241 //将获取的数据封装成对应的Student对象
    242 
    243 Student stu = new  Student(id, name, age);
    244 
    245 return stu;
    246 
    247 }
    248 
    249  
    250 
    251 } catch (Exception e) {
    252 
    253 // TODO: handle exception
    254 
    255 }finally {
    256 
    257 try {
    258 
    259 if(rs !=null) {
    260 
    261 rs.close();
    262 
    263 }
    264 
    265 } catch (SQLException e) {
    266 
    267 e.printStackTrace();
    268 
    269 }finally {
    270 
    271 JdbcUtil.close(conn, ps, rs);
    272 
    273 }
    274 
    275 }
    276 
    277  
    278 
    279 return null;
    280 
    281 }
    282 
    283  
    284 
    285 @Override
    286 
    287 public List<Student> selectList() {
    288 
    289 String sql = "select * from t_student";
    290 
    291 //创建list集合用于封装Student对象
    292 
    293 List<Student> stus = new ArrayList<>();
    294 
    295  
    296 
    297 Connection conn = null;
    298 
    299 PreparedStatement ps = null;
    300 
    301 ResultSet rs = null;
    302 
    303  
    304 
    305 try {
    306 
    307  
    308 
    309 conn = JdbcUtil.getConnection();
    310 
    311 // 3.创建语句对象
    312 
    313 ps = conn.prepareStatement(sql);
    314 
    315  
    316 
    317 // 4.执行SQL语句
    318 
    319 rs = ps.executeQuery();
    320 
    321 while(rs.next()) {
    322 
    323 //通过数据库数据和Java对应的数据类型获取对应的只
    324 
    325 int id = rs.getInt("id");
    326 
    327 String name = rs.getString("name");
    328 
    329 int age = rs.getInt("age");
    330 
    331 //System.out.println(id+","+name+","+age);
    332 
    333  
    334 
    335 //将获取的数据封装成对应的Student对象
    336 
    337 Student stu = new  Student(id, name, age);
    338 
    339 //将一个个Student对象添加到list集合中
    340 
    341 stus.add(stu);
    342 
    343 }
    344 
    345  
    346 
    347 } catch (Exception e) {
    348 
    349 // TODO: handle exception
    350 
    351 }finally {
    352 
    353 JdbcUtil.close(conn, ps, rs);
    354 
    355 }
    356 
    357  
    358 
    359 return stus;
    360 
    361 }
    362 
    363  
    364 
    365 } 

    5) 知识点补充,类加载器

    在项目的 类路径(src)下面创建一个 db.properties配置文件,专门配置连接数据库的账号密码

    如何使用类加载器加载配置文件

    [1]配置文件

    注:配置文件创建的位置

    配置文件一般都放在项目的src 源目录下面

    【2】加载代码

     1 package cn.sxt.jdbc.test;
     2 
     3  
     4 
     5 import static org.junit.Assert.*;
     6 
     7  
     8 
     9 import java.io.InputStream;
    10 
    11 import java.util.Properties;
    12 
    13  
    14 
    15 import org.junit.Test;
    16 
    17  
    18 
    19 public class PropertiesTest {
    20 
    21  
    22 
    23 @Test
    24 
    25 public void testName() throws Exception {
    26 
    27  
    28 
    29  /*
    30 
    31   * ClassLoader 类加载器
    32 
    33   * ClassLoader :可以从项目的类路径下面读取对应的配置文件返回一个输入流
    34 
    35   * ClassLoader 在程序运行的时候JVM已经为每一个项目都创建了一个,我们开发者只需要获取即可
    36 
    37   * 获取类加载器方式
    38 
    39   * 1、使用当前线程
    40 
    41   * ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    42 
    43   * 2、通过某一类的字节码实例也可以获取
    44 
    45   * ClassLoader classLoader = PropertiesTest.class.getClassLoader();
    46 
    47   */
    48 
    49 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    50 
    51 //使用类加载器获取项目 类路径下面的文件
    52 
    53 InputStream inputStream = classLoader.getResourceAsStream("db.properties");
    54 
    55  
    56 
    57  
    58 
    59 /*
    60 
    61  * Properties 是Map集合下面的一个 专门用于读取配置文件的对象
    62 
    63  * 可以读取当前类路径下面的  xxx.properites类型的配置文件
    64 
    65  *
    66 
    67  * xxx.properites的内容必须是key=value 键值对的数据
    68 
    69  */
    70 
    71  
    72 
    73 //1.创建Properties对象
    74 
    75 Properties p = new Properties();
    76 
    77  
    78 
    79 //2.加载配置文件
    80 
    81 p.load(inputStream);
    82 
    83  
    84 
    85 System.out.println(p);
    86 
    87  
    88 
    89 //获取具体某一个key对应的值
    90 
    91 String driverClassName = p.getProperty("driverClassName");
    92 
    93 System.out.println(driverClassName);
    94 
    95 }
    96 
    97 }
    98 
    99  

     [3] 效果

    8.连接池

    1)遇到的问题-引出连接池

    2) 连接池思想

    3) 连接池的概述

    Java,连接池使用javax.sql.DataSource接口来表示连接池.

    注意:DataSource仅仅只是一个接口,由各大服务器厂商来实现(Tomcat.JBoss,阿里巴巴).

    常用的DataSource的实现:

      DBCP:  Spring推荐的

      C3P0:  Hibernate推荐的

      Druid : (德鲁伊)阿里巴巴开源的,性能最好,速度最快

    DataSource(数据源)和连接池(Connection Pool)是同一个.

    4) 使用连接池和不使用连接池的区别在哪里

    从代码上:

    不使用连接池: Conenction对象由DriverManager获取.

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

    使用连接池:

      如何创建DataSource对象,如何在DataSource中设置url,账号,密码.

      Connection conn = DataSource对象.getConnection();

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

    使用连接池的时候:

      释放资源: Connection对象.close():

      是把Connection放回给连接池,而不是和数据库断开.

     5) Druid连接池的使用

    [1] 准备druid 连接池jar包到项目

      1 package cn.sxt.jdbc.test;
      2 
      3  
      4 
      5 import static org.junit.Assert.*;
      6 
      7  
      8 
      9 import java.io.InputStream;
     10 
     11 import java.io.Reader;
     12 
     13 import java.sql.Connection;
     14 
     15 import java.util.Properties;
     16 
     17  
     18 
     19 import javax.sql.DataSource;
     20 
     21  
     22 
     23 import org.junit.Test;
     24 
     25  
     26 
     27 import com.alibaba.druid.pool.DruidDataSource;
     28 
     29 import com.alibaba.druid.pool.DruidDataSourceFactory;
     30 
     31 import com.alibaba.druid.pool.DruidPooledConnection;
     32 
     33  
     34 
     35 public class DataSourceTest {
     36 
     37 // 直接创建连接池对象
     38 
     39 @Test
     40 
     41 public void testName() throws Exception {
     42 
     43 // 1.创建连接池对象
     44 
     45 DruidDataSource ds = new DruidDataSource();
     46 
     47 // 2.设置连接数据库的账号密码
     48 
     49 ds.setDriverClassName("com.mysql.jdbc.Driver");
     50 
     51 ds.setUrl("jdbc:mysql://localhost:3306/jdbcdemo");
     52 
     53 ds.setUsername("root");
     54 
     55 ds.setPassword("root");
     56 
     57 ds.setMaxActive(10);// 最大连接数
     58 
     59 // 3.获取连接对象
     60 
     61 Connection conn = ds.getConnection();
     62 
     63 System.out.println(conn);
     64 
     65 }
     66 
     67  
     68 
     69 // 使用工厂对象创建连接池对象,工厂对象的好处,不需要直接设置账号密码等等,只需要将
     70 
     71 // 连接数据库的账号密码等等以指定的 key的名称配置到 xxx.properties文件中即可,工厂对象底层自动读取
     72 
     73 @Test
     74 
     75 public void testDataSourceByFactory() throws Exception {
     76 
     77  
     78 
     79 // 1.获取类加载器用于加载clsspath下面的 配置文件
     80 
     81 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
     82 
     83 // 2.读取druid.properties配置文件
     84 
     85 InputStream inputStream = classLoader.getResourceAsStream("druid.properties");
     86 
     87 // 3.创建Properties对象,并读取配置文件对应的输入流
     88 
     89 Properties p = new Properties();
     90 
     91 p.load(inputStream);
     92 
     93  
     94 
     95 // 4.创建连接池对象
     96 
     97 DataSource ds = DruidDataSourceFactory.createDataSource(p);
     98 
     99 // 5.获取连接对象
    100 
    101 Connection conn = ds.getConnection();
    102 
    103 System.out.println(conn);
    104 
    105 }
    106 
    107 }

    [2]db.propperties

    [3]使用Druid抽取的工具类

    9. 事务

    案例:银行转账:从张无忌账户上给赵敏转1000.

    准备:account(账户表):

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

    id            name(账号,唯一)           balance(余额)

    1             张无忌                    20000

    2             赵敏                      0

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

    转账的思路:

       1.检查张无忌的账号余额是否大于等于1000.

            SQL: SELECT balance FROM account WHERE name = '张无忌' AND balance >=1000

            余额>=1000:GOTO 2:

            余额 <1000:提示:,你的余额不足.

       2.在张无忌的账号余额上减少1000.

            SQL: UPDATE account SET balance = balance-1000 WHERE name = '张无忌'

       3.在赵敏的账户余额尚增加1000.

            SQL: UPDATE account SET balance = balance+1000 WHERE name = '赵敏'

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

    注意:在第二步和第三步之间,停电了.

         使用异常模拟停电:System.out.println(1/0);

    1)事务概述

    事务(Transaction,简写为tx):

    在数据库中,所谓事务是指一组逻辑操作单元,使数据从一种状态变换到另一种状态。

    为确保数据库中数据的一致性,数据的操纵应当是离散的成组的逻辑单元:

      当每个逻辑操作单元全部完成时,数据的一致性可以保持,

      而当这个单元中的一部分操作失败,整个事务应全部视为错误,所有从起始点以后的操作应全部回退到开始状态。

    事务的操作:先定义开始一个事务,然后对数据作修改操作,这时如果提交(commit),这些修改就永久地保存下来,如果回退(rollback),数据库管理系统将放弃您所作的所有修改而回到开始事务时的状态。

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

    事务的ACID属性:

    1. 原子性(Atomicity
    原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。 

    2. 一致性(Consistency
    事务必须使数据库从一个一致性状态变换到另外一个一致性状态。(数据不被破坏)

    3. 隔离性(Isolation

    事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

    4. 持久性(Durability
    持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响

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

    事务:指构成单个逻辑工作单元的操作集合

    事务处理:保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。当在一个事务中执行多个操作时,要么所有的事务都被提交(commit),要么整个事务回滚(rollback)到最初状态

    处理事务的两个动作:

           提交:commit:   当整个事务中,所有的逻辑单元都正常执行成功.  ---->提交事务.---数据已经提交,不能更改.

           回滚:rollback: 当整个事务中,有一个逻辑单元执行失败,        ---->回滚事务.  

                          撤销该事务中的所有操作--->恢复到最初的状态.

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

    如何在代码中去处理事务:

    1.JDBC,事务是默认自动提交的.  必须先设置事务为手动提交.

    connection对象.setAutoCommit(false);//设置事务为手动提交.

    2.手动的提交事务.

    connection对象.commit();

    3.若出现异常必须回滚事务:

       不回滚事务,总余额依然是正确的. 若不回滚事务,不会释放数据库资源.

       connection对象.rollback();

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

    1.JDBC在事务是默认提交的,那是在什么时候提交的.

    在执行一个DML/DDL操作的时候,就已经提交事务了.

    2.针对于CRUD操作. 只有DML操作才有事务,查询操作没有事务.

      但是,我们一般会把查询也放在事务里面.

    1. 以后,凡是发现自己编写的代码是正确的,测试也通过,但是就是数据库表中的数据不变----->事务没提交的问题.

     

     

    4.MySQL,InnoDB支持外键.支持事务,MyISAM不支持外键,不支持事务.

    InnoDB存储引擎: 支持事务,支持外键,但是查询效率略低,(金融,理财,p2p

    MyISAM存储引擎:不支持事务和外键,但是查询效率较高(新闻网站)

    Oracle 不存在存储引擎,都有事务

    2)事务处理代码

     1 public class TransactionTest {
     2 
     3 @Test
     4 
     5 public void testName() throws Exception {
     6 
     7 Connection conn = null;
     8 
     9 Statement st = null;
    10 
    11 ResultSet rs = null;
    12 
    13 try {
    14 
    15 conn = DruidUtil.getConnection();
    16 
    17 //将事务设置为手动提交
    18 
    19 conn.setAutoCommit(false);
    20 
    21  
    22 
    23 st = conn.createStatement();
    24 
    25 // 1.检查张无忌的账号余额是否大于等于1000.
    26 
    27 rs = st.executeQuery("SELECT balance FROM account WHERE name = '张无忌' AND balance >=1000");
    28 
    29 if(!rs.next()) {
    30 
    31 throw new RuntimeException("亲,您的账户余额不够");
    32 
    33 }
    34 
    35 // 余额>=1000:GOTO 2:
    36 
    37 // 余额 <1000:提示:亲,你的余额不足.
    38 
    39 // 2.在张无忌的账号余额上减少1000.
    40 
    41 st.executeUpdate("UPDATE account SET balance = balance-1000 WHERE name = '张无忌'");
    42 
    43  
    44 
    45 System.out.println(1/0);
    46 
    47  
    48 
    49 // 3.在赵敏的账户余额尚增加1000.
    50 
    51 st.executeUpdate("UPDATE account SET balance = balance+1000 WHERE name = '赵敏'");
    52 
    53  
    54 
    55 //提交事务
    56 
    57 conn.commit();
    58 
    59  
    60 
    61  
    62 
    63 } catch (Exception e) {
    64 
    65 e.printStackTrace();
    66 
    67 //回滚事务
    68 
    69 conn.rollback();
    70 
    71  
    72 
    73 }finally {
    74 
    75 DruidUtil.close(conn, st, rs);
    76 
    77 }
    78 
    79  
    80 
    81 }
    82 
    83 }
  • 相关阅读:
    体验一下:AndroidX
    Android研发技术的进阶之路
    App 冷启动与热启动及启动白屏优化
    Android Q 正式命名为 Android 10
    Android开发学习路线的七个阶段和步骤
    安卓旅途之——开发数独(一)
    项目总结
    小组互评与自评
    典型用户与场景
    第二个Sprint计划
  • 原文地址:https://www.cnblogs.com/qq2267711589/p/10887536.html
Copyright © 2020-2023  润新知