JavaWeb笔记之JavaWeb JDBC

//Author 流云

//Version 1.0
   

一. 引言

1.1 如何操作数据库
使用客户端工具访问数据库,需要手工建立连接,输入用户名和密码登录,编写 SQL 语句,点击执行,查看操作结果(结果集或受影响行数)。

   
1.2 实际开发中,不会采用数据库客户端操作
在实际开发中,当用户的数据发生改变时,不可能通过客户端操作执行 SQL 语句,因为操作量过大,无法保证效率和正确性。
    

二. JDBC

2.1 介绍
JDBC(Java Database Connectivity) Java 连接数据库的规范(标准),可以使用 Java 语言连接数据库完成 CRUD 操作。
     
2.2 核心思想
Java 中定义了访问数据库的接口,可以为多种关系型数据库提供统一的访问方式。由数据库厂商提供驱动实现类(Driver 数据库驱动)。

  
2.3 驱动包
mysql-connector-java-5.1.X 适用于 5.X 版本
mysql-connector-java-8.0.X 适用于 8.X版本
  
2.4 常用类
JDBC 是由多个接口和类进行功能实现。

    
2.5 环境搭建
在项目下新建 lib 文件夹,用于存放 jar 文件。
将 mysql 驱动mysql-connector-java-5.1.X复制到项目的 lib 文件夹中。
选中 lib 文件夹右键 Add as Libraay,点击 OK。
    

三. 开发步骤

3.1 注册驱动
使用 Class.forName("com.mysql.jdbc.Driver");手动加载字节码文件到 JVM 中。
Class.forName("com.mysql.jdbc.Driver");//加载驱动
  
3.2 连接数据库
通过 DriverManager.getConnection(url,user,password) 获取数据库连接对象。
        URL:jdbc:mysql://localhost:3306/database
        username:root
        password:1234
Connection conn = 
DriverManager.getConnection("jdbc:mysql://localhost:3306/database?
useUnicode=true&characterEncoding=utf8", "root","1234");
  
URL(Uniform Resource Locator) 统一资源定位符:由协议、IP、端口、SID(程序实例名称)组成。
   
3.3 获取执行对象
通过 Connection 对象获得 Statement 对象,用于对数据库进行通用访问。
Statement statement = conn.createStatement();
  
3.4 执行SQL 语句
执行 SQL 语句并接收执行结果。
String sql ="INSERT INTO t_jobs(JOB_ID,JOB_TITLE,MIN_SALARY,MAX_SALARY)
VALUES('JAVA_Le','JAVA_Lecturer',4000,10000);";int result = statement.executeUpdate(sql);//执行SQL语句并接收结果
   
注意:在编写 DML 语句时,一定要注意字符串参数的符号是单引号 '值'。
DML 语句:增删改时,返回受影响行数(int 类型)。
DQL 语句:查询时,返回结果数据(ResultSet 结果集)。
    
3.5 处理结果
接受处理操作结果。
if(result == 1){System.out.println("Success");
}
   
受影响行数:逻辑判断、方法返回。
查询结果集:迭代、依次获取。
  
3.6 释放资源
遵循先开后关原则,释放所使用到的资源对象。
statement.close();
conn.close();
   
3.7 综合案例
整合以上核心六步,实现向数据库表中插入一条数据。
package com.jdbc;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;public class DeleteJdbc {public static void main(String[] args) throws Exception{//1.加载驱动Class.forName("com.mysql.jdbc.Driver");//2.获得连接对象Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/companydb","root","1234");//3.获得执行SQL的对象Statement statement = connection.createStatement();//4.执行SQL语句,并接收结果int result = statement.executeUpdate("delete from t_jobs where job_id = 'H5_mgr';");//5.处理结果if(result==1){System.out.println("删除成功!");}else{System.out.println("删除失败!");}//6.释放资源statement.close();connection.close();}
}
  

四. ResultSet

在执行查询 SQL 后,存放查询到的结果集数据。
  
4.1 接收结果集
ResultSet rs = statement.executeQuery(sql);
ResultSet rs= statement.executeQuery("SELECT * FROM t_employees;");
  
4.2 遍历结果集
ResultSet 以表(table)结构进行临时结果的存储,需要通过 JDBC API 将其中数据进行依次获取。
        数据行指针:初始位置在第一行数据前,每调用一次 boolean next()方法ResultSet 的指针向下移动一行,结果为 true,表示当前行有数据。
        rs.getXxx(整数);代表根据列的编号顺序获得,从 1 开始。
        rs.getXxx("列名");代表根据列名获得。
boolean next() throws SQLException //判断 rs 结果集中下一行是否存在数据
  
4.2.1 遍历方法
int getInt(int columnIndex) throws SQLException //获得当前行第N列的int值
int getInt(String columnLabel) throws SQLException //获得当前行columnLabel列的int值double getDouble(int columnIndex) throws SQLException //获得当前行第N列的double值
double getDouble(String columnLabel) throws SQLException //获得当前行columnLabel列的double值String getString(int columnIndex) throws SQLException //获得当前行第N列的String值
String getString(String columnLabel) throws SQLException //获得当前行columnLabel列的String值......
  
注意:列的编号从 1 开始。
  
4.3 综合案例
对 t_jobs 表中的所有数据进行遍历。
    
4.3.1 根据列名
package com.www.test;import java.sql.*;public class JobsQuery {public static void main(String[] args) {//1.加载驱动Class.forName("com.mysql.jdbc.Driver");//2.获取数据库连接对象Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/product", "root", "1234");//3.获取发送 sql 语句对象Statement statement = connection.createStatement();//4.执行 SQL 语句并接收结果集ResultSet resultSet = statement.executeQuery("select * from t_jobs");//5 处理结果集while(resultSet.next()){//5.1有数据,依据列名获取数据String job_id = resultSet.getString("job_id");String job_title = resultSet.getString("job_title");int min_salary = resultSet.getInt("min_salary");int max_salary = resultSet.getInt("max_salary");System.out.println(job_id+"\t"+job_title+"\t"+min_salary+"\t"+max_salary);}//6.释放资源rs.close();statement.close();connection.close();}
}
    
4.3.2 根据编号
//。。。。与上无异
while(resultSet.next()){//5.2有数据,依据列名获取数据String job_id = resultSet.getString(1);String job_title = resultSet.getString(2);int min_salary = resultSet.getInt(3);int max_salary = resultSet.getInt(4);System.out.println(job_id+"\t"+job_title+"\t"+min_salary+"\t"+max_salary);
}
//释放资源
  

五. 常见错误

java.lang.ClassNotFoundException:找不到类(类名书写错误、没有导入jar包)。
java.sql.SQLException:与sql语句相关的错误 (约束错误、表名列名书写错误) 建议:在客户端工具中测试SQL语句之后再粘贴在代码中。
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 原因:列值Sting类型没有加单引号。
Duplicate entry '1' for key 'PRIMARY' 原因,主键值已存在或混乱,更改主键值或清空表。
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'password' in 原因:可能输入的值的类型不对,确定是否插入的元素时对应的值的类型正确。
    

六. 登录案例

6.1 创建表
创建一张用户表 User
        id ,主键、自动增长。
        用户名,字符串类型,唯一、非空
        密码,字符串类型,非空
        手机号码,字符串类型
插入 2 条测试语句
   
6.2 实现登录
通过控制台用户输入用户名和密码。
用户输入的用户名和密码作为条件,编写查询 SQL 语句。
如果该用户存在,提示登录成功,反之提示失败。
    

七. SQL注入

7.1 介绍
用户输入的数据中有 SQL 关键字或语法并且参与了 SQL 语句的编译,导致 SQL 语句编译后的条件含义为 true,一直得到正确的结果。这种现象称为 SQL 注入。
  
7.2 方案
由于编写的 SQL 语句是在用户输入数据,整合后再进行编译。所以为了避免 SQL 注入的问题,我们要使 SQL 语句在用户输入数据前就已进行编译成完整的 SQL 语句,再进行填充数据。
  

八. PreparedStatement

PreparedStatement 继承了 Statement 接口,执行 SQL 语句的方法无异。
  
8.1 应用
作用:
预编译SQL 语句,效率高。
安全,避免SQL注入 。
可以动态的填充数据,执行多个同构的 SQL 语句。
  
8.1.1 参数标记
//1.预编译 SQL 语句
PreparedStatement pstmt = conn.prepareStatement("select * from user where username=? and password=?");
  
注意:JDBC中的所有参数都由 ?符号占位,这被称为参数标记。在执行SQL语句之前,必须为每个参数提供值。 
    
8.1.2 动态参数绑定
pstmt.setXxx(下标,值) 参数下标从 1 开始,为指定参数下标绑定值。
//1.预编译 SQL 语句
PreparedStatement pstmt = conn.prepareStatement("select * from user where username=? and password=?");//2.为参数下标赋值
pstmt.setString(1,username);
pstmt.setString(2,password);
  

九. 封装工具类

在实际JDBC的使用中,存在着大量的重复代码:例如连接数据库、关闭数据库等这些操作!
我们需要把传统的JDBC代码进行重构,抽取出通用的JDBC工具类!以后连接任何数据库、释放资源都可以使用这个工具类。

  
9.1 重用性方案
封装获取连接、释放资源两个方法。
        提供public static Connection getConnection(){}方法。
        提供public static void closeAll(Connection conn , Statement sm , ResultSet rs){}方法。
  
9.1.1 实现
package com.jdbc;import java.sql.*;/**
* 重用性方案
* 获取连接
* 释放资源
*/public class DBUtils {static {//类加载,执行一次!try {Class.forName("com.mysql.jdbc.Driver");} catch (ClassNotFoundException e) {e.printStackTrace();}}//1.获取连接public static Connection getConnection() {Connection connection = null;try {connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/companydb", "root","1234");} catch (SQLException e) {e.printStackTrace();}return connection;}//2.释放资源public static void closeAll(Connection connection, Statement statement, ResultSet resultSet) {try {if (resultSet != null) {resultSet.close();}if (statement != null) {statement.close();}if (connection != null) {connection.close();}} catch (SQLException e) {e.printStackTrace();}}
}
  
9.2 跨平台方案
定义public static final Properties prop = new Properties(); //读取配置文件的Map。
定义static{
        //首次使用工具类时,加载驱动
InputStream is = JDBCUtil.class.getResourceAsStream("路径"); //通过复用本类自带流,读取jdbc.properties配置文件。classPath = bin
prop.load(is); //通过prop对象将流中的配置信息分割成键值对。
String driverName = prop.getProperty("driver"); //通过driverName的键获取对应的值(com.mysql.jdbc.Driver)
Class.forName(driverName); //加载驱动。
}
    
9.2.1 实现
在src 目录下新建 db.properties 文件。
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mydb3
user=root
password=123456
    
工具类的封装。
package com.jdbc2;import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;public class DBUtils {private static final Properties PROPERTIES = new Properties();//存储配置文件的mapstatic {InputStream is = DBUtils.class.getResourceAsStream("/db.properties");try {PROPERTIES.load(is);//通过流,将配置文件内容加载到properties集合Class.forName(PROPERTIES.getProperty("driver"));} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}}public static Connection getConnection() {Connection connection = null;try {connection = DriverManager.getConnection(PROPERTIES.getProperty("url"),PROPERTIES.getProperty("username"), PROPERTIES.getProperty("password"));} catch (SQLException e) {e.printStackTrace();}return connection;}public static void closeAll(Connection connection, Statement statement, ResultSet resultSet) {try {if (resultSet != null) {resultSet.close();}if (statement != null) {statement.close();}if (connection != null) {connection.close();}} catch (SQLException e) {e.printStackTrace();}}
}
   

十. ORM

ORM(Object Relational Mapping)。
从数据库查询到的结果集(ResultSet)在进行遍历时,逐行遍历,取出的都是零散的数据。在实际应用开发中,我们需要将零散的数据进行封装整理。
   
10.1 实体类
一行数据中,多个零散的数据进行整理。
通过entity的规则对表中的数据进行对象的封装。
表名=类名;列名=属性名;提供各个属性的get、set方法。
提供无参构造方法、(视情况添加有参构造)。
      
10.1.1 ORM应用
entity实体类
package com.www.test;public class T_Jobs {private String job_id;private String job_title;private int min_salary;private int max_salary;@Overridepublic String toString() {return "T_Jobs{" +"job_id='" + job_id + '\'' +", job_title='" + job_title + '\'' +", min_salary=" + min_salary +", max_salary=" + max_salary +'}';}public String getJob_id() {return job_id;}public void setJob_id(String job_id) {this.job_id = job_id;}public String getJob_title() {return job_title;}public void setJob_title(String job_title) {this.job_title = job_title;}public int getMin_salary() {return min_salary;}public void setMin_salary(int min_salary) {this.min_salary = min_salary;}public int getMax_salary() {return max_salary;}public void setMax_salary(int max_salary) {this.max_salary = max_salary;}public T_Jobs() {}public T_Jobs(String job_id, String job_title, int min_salary, int max_salary) {this.job_id = job_id;this.job_title = job_title;this.min_salary = min_salary;this.max_salary = max_salary;}
}
   
查询结果封装
package com.www.test;import java.sql.*;public class JobsQuery {public static void main(String[] args) {Connection connection = null;Statement statement = null;ResultSet resultSet = null;String URL = "jdbc:mysql://localhost:3306/product";String user = "root";String password = "1234";try {//1.加载驱动Class.forName("com.mysql.jdbc.Driver");//2.获取数据库连接对象connection = DriverManager.getConnection(URL, user, password);//3.编写 SQL 语句String sql = "select * from t_jobs";//4.获取发送 sql 语句对象statement = connection.createStatement();//5.执行 SQL 语句并接收结果集resultSet = statement.executeQuery(sql);//5.1使用 while 循环判断下一行是否有数据while(resultSet.next()){//5.2有数据,依据列名获取数据String job_id = resultSet.getString(1);String job_title = resultSet.getString(2);int min_salary = resultSet.getInt(3);int max_salary = resultSet.getInt(4);//5.3 创建实体类对象T_Jobs t_jobs = new T_Jobs();//5.4 每列数据对应属性进行赋值t_jobs.setJob_id(job_id);t_jobs.setJob_title(job_title);t_jobs.setMin_salary(min_salary);t_jobs.setMax_salary(max_salary);System.out.println(t_jobs);}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException e) {e.printStackTrace();} finally {try {//6.释放资源if (resultSet != null) {resultSet.close();}if (statement != null) {statement.close();}if (connection != null) {connection.close();}} catch (SQLException e) {e.printStackTrace();}}}
}
   

十一. 数据访问对象

DAO 实现了业务逻辑与数据库访问相分离。
        对同一张表的所有操作封装在XxxDaoImpl对象中。
        根据增删改查的不同功能实现具体的方法(insert、update、delete、select、 selectAll)。

  
11.1 创建数据库
创建一张表 Person,有以下列:
        id:int,主键,自动增长
        name:varchar(20) 非空
        age:int 非空
        bornDate:Date
        email:字符串
        address:字符串
   
11.2 封装实体类
创建entity实体类 Person,编写属性私有化,构造方法,get/set 方法。
  
11.3 编写 DaoImpl 类
编写 DaoImpl 类,提供增删改查方法,使用 JDBC 开发步骤,完成功能。
package com.person;import sun.awt.image.DataBufferNative;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;/**
* 增、删、改、查单个、查所有
* 只做数据库访问操作!不参与逻辑判断
* 数据库一张表的访问的操作复用!
*/public class PersonDaoImpl {//新增public int insert(Person person){Connection connection = null;PreparedStatement preparedStatement = null;String sql = "insert into person(name,age,borndate,email,address) values(?,?,?,?,?);";try {connection = DBUtils.getConnection();preparedStatement = connection.prepareStatement(sql);preparedStatement.setString(1,person.getName());preparedStatement.setInt(2,person.getAge());preparedStatement.setDate(3,null);preparedStatement.setString(4,person.getEmail());preparedStatement.setString(5,person.getAddress());int result = preparedStatement.executeUpdate();return result;} catch (SQLException e) {e.printStackTrace();}finally {DBUtils.closeAll(connection,preparedStatement,null);}return 0;}//修改public int update(Person person){Connection connection =null;PreparedStatement preparedStatement = null;String sql = "update person setname=?,age=?,borndate=?,email=?,address=? where id = ?";try {connection = DBUtils.getConnection();preparedStatement = connection.prepareStatement(sql);preparedStatement.setString(1,person.getName());preparedStatement.setInt(2,person.getAge());preparedStatement.setDate(3,null);preparedStatement.setString(4,person.getEmail());preparedStatement.setString(5,person.getAddress());preparedStatement.setInt(6,person.getId());int result = preparedStatement.executeUpdate();return result;} catch (SQLException e) {e.printStackTrace();}finally {DBUtils.closeAll(connection,preparedStatement,null);}return 0;}//删除public int delete(int id){Connection connection = null;PreparedStatement preparedStatement = null;String sql = "delete from person where id= ?;";connection = DBUtils.getConnection();try {preparedStatement = connection.prepareStatement(sql);preparedStatement.setInt(1,id);int result = preparedStatement.executeUpdate();return result;} catch (SQLException e) {e.printStackTrace();}finally {DBUtils.closeAll(connection,preparedStatement,null);}return 0;}//查单个public Person select(int id){Connection connection = null;PreparedStatement preparedStatement = null;ResultSet resultSet = null;String sql = "select * from person where id = ?;";Person person = null;try {connection = DBUtils.getConnection();preparedStatement = connection.prepareStatement(sql);preparedStatement.setInt(1,id);resultSet = preparedStatement.executeQuery();if(resultSet.next()){person = new Person();int pid= resultSet.getInt("id");String name = resultSet.getString("name");int age = resultSet.getInt("age");Date bornDate = resultSet.getDate("borndate");String email = resultSet.getString("email");String address = resultSet.getString("address");person.setId(pid);person.setName(name);person.setAge(age);person.setBornDate(bornDate);person.setEmail(email);person.setAddress(address);}return person;} catch (SQLException e) {e.printStackTrace();}finally {DBUtils.closeAll(connection,preparedStatement,resultSet);}return null;}//查所有public List<Person> selectAll(){Connection connection = null;PreparedStatement preparedStatement = null;ResultSet resultSet = null;Person person = null;List<Person> personList = new ArrayList<>();try {connection = DBUtils.getConnection();preparedStatement = connection.prepareStatement("select * from person;");resultSet = preparedStatement.executeQuery();while(resultSet.next()){int pid= resultSet.getInt("id");String name = resultSet.getString("name");int age = resultSet.getInt("age");Date bornDate = resultSet.getDate("borndate");String email = resultSet.getString("email");String address = resultSet.getString("address");person = new Person(pid,name,age,bornDate,email,address);personList.add(person);}return personList;} catch (Exception e) {e.printStackTrace();}return null;}
}
  

十二. 三层架构

12.1 什么是三层
 表示层:
命名:XXXView
职责:收集用户的数据和需求、展示数据。
   
业务逻辑层:
命名:XXXServiceImpl
职责:数据加工处理、调用DAO完成业务实现、控制事务。
   
数据访问层:
命名:XXXDaoImpl
职责:向业务层提供数据,将业务层加工后的数据同步到数据库。

   
12.2 三层搭建
utils 存放工具类(DBUtils)
entity 存放实体类(Person)
dao 存放 DAO 接口(PersonDao)
        impl 存放 DAO 接口实现类(PersonDaoImpl)
service 存放 service 接口(PersonService)
        impl 存放 service 接口实现类(PersonServiceImpl)
view 存放程序启动类(main)
程序设计时,考虑易修改、易扩展,为Service层和DAO层设计接口,便于未来更换实现类。
     

十三. 通用工具类

在DAO层中,对数据库表的增、删、改、查操作存在代码冗余,可对其进行抽取封装DaoUtils工具类实现复用。
  
13.1通用DML
/**
* 将所有数据表的操作,抽离成一个公用的方法;
* @Param sql 语句
* @Param sql语句对应的参数
* @return
*/
public static boolean executeDML(String sql,Object... params){try {//获取连接Connection connection = getConnection();//获取预处理的对象PreparedStatement ps = connection.prepareStatement(sql);//设置参数if(null != params){for(int i = 0 ; i < params.length ; i++){//1:给占位符设置参数;2:获取参数ps.setObject(i+1,params[i]);}}int i = ps.executeUpdate();close(null,ps,connection);return i > 0;} catch (SQLException sqlException) {sqlException.printStackTrace();}return false;
}
  
13.2 通用DQL
/**
* 通用的查询;需要将我们的数据表信息,封装到List里面进行返回
* @param sql 查询语句
* @param cls 实体类的字节码对象
* @param params 查询语句里面的占位符
* @param <T> 实体类类型泛型
* @return 就是我们查询到的数据集合
*/public static <T> List<T> executeDQL(String sql, Class<T> cls , Object...params) {try {Connection connection = getConnection(); //获取连接//获取预处理sqlPreparedStatement preparedStatement = connection.prepareStatement(sql);//设置参数if(null != params){for(int i = 0 ; i < params.length ; i++){preparedStatement.setObject(i+1,params[i]);}}//执行查询 得到结果集ResultSet resultSet = preparedStatement.executeQuery();//获取元数据(我们的列名)ResultSetMetaData metaData = resultSet.getMetaData();//列的总数int columnCount = metaData.getColumnCount();//用来保存我们所有的表数据List<T> list = new ArrayList<T>();T t;//用来保存我们一条数据//遍历结果集while(resultSet.next()){ //每一行记录的遍历过程中t = cls.newInstance();//根据字节码文件,构建一个实体类的对象//获取所有列的数据for(int i = 1 ; i <= columnCount ; i++){//你的查询语句有时候有别名String columnLabel = metaData.getColumnLabel(i);//根据列名获取我们的记录Object object = resultSet.getObject(columnLabel);//需要将拿到的这一列的记录,放到t对象指定的属性里面;//需要拿到这个t对象的属性,然后赋值;//解决方案2: 如果Object是NULL没有必要设置了if(null != object){try {Field field = cls.getDeclaredField(columnLabel);//根据属性的名称通过反射获取他的属性对象field.setAccessible(true);field.set(t,object);} catch (NoSuchFieldException e) {//代表我们当前这个实体类里面,没有这个属性}}}//需要将t对象保存到listlist.add(t);}close(resultSet,preparedStatement,connection);return list;} catch (SQLException sqlException) {sqlException.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();}return null;
}
   
13.3 Apache的DbUtils
13.3.1 简介
DbUtils是Java编程中数据库操作实用小工具,小巧、简单、实用。
        对于数据表的查询操作,可以把结果转换为List、Array、Set等集合。便于操作。
        对于数据表的DML操作,也变得很简单(只需要写SQL语句)。
  
13.3.2 API
ResultSetHandler接口:转换类型接口
        BeanHandler类:实现类,把一条记录转换成对象
        BeanListHandler类:实现类,把多条记录转换成List集合。
        ScalarHandler类:实现类,适合获取一行一列的数据。
QueryRunner:执行sql语句的类
        增、删、改:update();
        查询:query();
  
13.3.3 使用步骤
导入jar包
        mysql连接驱动jar包
        druid-1.1.5.jar
        database.properties配置文件
        commons-dbutils-1.6.jar
     
13.3.4 代码
package com.project.utils;import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;/**
* 连接池工具类
*/public class DBUtils {private static DruidDataSource dataSource;static {Properties properties = new Properties();InputStream is = DBUtils.class.getResourceAsStream("/database.properties");try {properties.load(is);dataSource = (DruidDataSource)DruidDataSourceFactory.createDataSource(properties);} catch (IOException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}}// 返回一个数据源public static DataSource getDataSource(){return dataSource;}
}
package com.project.dao.impl;import com.project.dao.UserDao;
import com.project.entity.User;
import com.project.utils.DBUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import java.sql.SQLException;
import java.util.List;public class UserDaoImpl implements UserDao {//1.创建QueryRunner对象,并传递一个数据源对象private QueryRunner queryRunner = new QueryRunner(DBUtils.getDataSource());@Overridepublic int insert(User user) {Object[] params={user.getId(),user.getUsername(),user.getPassword(),user.getSex(),user.getEmail(),user.getAddress()};try {return queryRunner.update("insert into user(id,username,password,sex,email,address) values(?,?,?,?,?,?)",params);} catch (SQLException e) {e.printStackTrace();}return 0;}@Overridepublic int update(User user) {Object[] params={user.getUsername(),user.getPassword(),user.getSex(),user.getEmail(),user.getAdd ress(),user.getId()};try {return queryRunner.update("update user setusername=?,password=?,sex=?,email=?,address=? where id = ?",params);} catch (SQLException e) {e.printStackTrace();}return 0;}@Overridepublic int delete(int id) {try {return queryRunner.update("delete from user where id = ?",id);} catch (SQLException e) {e.printStackTrace();}return 0;}@Overridepublic User select(int id) {try {//把查询到的记录封装成 指定对象return queryRunner.query("select * from user where id = ?", newBeanHandler<User>(User.class), id);} catch (SQLException e) {e.printStackTrace();}return null;}/*** 查询所有* @return*/@Overridepublic List<User> selectAll() {try {return queryRunner.query("select * from user;",newBeanListHandler<User>(User.class));} catch (SQLException e) {e.printStackTrace();}return null;}
}
  

十四. 连接池

在程序初始化时,预先创建指定数量的数据库连接对象存储在池中。当需要连接数据库时,从连接池中取出现有连接;使用完毕后,也不会进行关闭,而是放回池中,实现复用,节省资源。
资源重用。
更快的系统响应速度。
新的资源分配手段。
统一的连接管理,避免数据库连接泄漏。
  
14.1 Druid
14.1.1 步骤
创建 druid.properties 配置文件。
引入druid-xxx.jar 文件。
  
14.1.2 druid.properties
#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mytest
username=root
password=123456
#<!-- 初始化连接 -->
initialSize=10
#最大连接数量
maxActive=50
#<!-- 最小空闲连接 -->
minIdle=5
#<!-- 超时等待时间以毫秒为单位 60000毫秒/1000等于60秒 -->
maxWait=5000
    
14.1.3 连接池工具类
public class DbUtils {//声明连接池对象private static DruidDataSource ds;static{//实例化配置对象Properties properties=new Properties();try {//加载配置文件内容properties.load(DbUtils.class.getResourceAsStream("druid.properties"));ds = (DruidDataSource)DruidDataSourceFactory.createDataSource(properties);} catch (IOException e) {e.printStackTrace();}}//获取连接对象public static Connection getConnection() {try {return ds.getConnection();} catch (SQLException e) {e.printStackTrace();}return null;}//释放资源。。
}
   
14.2 HikariCP
引入HikariCP-xxx.jar 文件。
/*
一、主要配置
1、dataSourceClassName
这是DataSourceJDBC驱动程序提供的类的名称。请注意,如果您正在使用jdbcUrl“旧式”基于DriverManager的JDBC驱动程序配置,则不需要此属性 。 默认值:无
2、jdbcUrl
请注意,如果使用此属性,您仍然可以使用DataSource属性来配置您的驱动程序,实际上建议您使用URL本身中指定的驱动程序参数。 默认值:无
3、username
此属性设置从基础驱动程序获取连接时使用的默认身份验证用户名。
4、password
此属性设置从基础驱动程序获取连接时使用的默认身份验证密码。
*/
public static void main(String[] args) throws SQLException {HikariConfig hikariConfig = new HikariConfig();//设置urlhikariConfig.setJdbcUrl("jdbc:mysql://localhost:3306/mytest?characterEncoding=UTF-8");//数据库帐号hikariConfig.setUsername("root");//数据库密码hikariConfig.setPassword("123456");HikariDataSource ds = new HikariDataSource(hikariConfig);
}
    

十五 . 批处理

addBatch(); 添加到批处理
executeBatch(); 执行批处理
clearBatch(); 清空批处理
//如果保存1w条记录
String sql = "insert into userinfo(uname,upass) values(?,?)";
Connection connection = DBUtilPool.getConnectionByDruid();
long start = System.currentTimeMillis();
PreparedStatement preparedStatement = connection.prepareStatement(sql);
for(int i = 0 ; i < 10000 ; i++){preparedStatement.setObject(1,"jack"+i);preparedStatement.setObject(2,"aaaa"+i);preparedStatement.addBatch(); //将当前的sql预编译好以后,加到批处理; 不会直接执行到数据库里面if(i % 500 == 0){preparedStatement.executeBatch(); //执行我们批处理preparedStatement.clearBatch(); //把上面的执行了,需要清空}
}
preparedStatement.executeBatch(); //最后一次进行批处理
long end = System.currentTimeMillis();
System.out.println("");
System.out.println(end-start);
  

十六. 事务

16.1 业务
代表用户完成的一个业务功能,可以由一个或多个DAO的调用组成。(软件所提供的一个功能都叫业务)。
  
16.2 service层

   
16.3 转账案例
BEGIN ;-- 代表我们开启了一个事务
UPDATE user_acount SET umoney = umoney-200 WHERE uname = 'jack';-- 断网了 断电了
UPDATE user_acount SET umoney = umoney+200 WHERE uname = 'rose';ROLLBACK -- 回滚事务(代表整个事务执行失败)
COMMIT; -- 提交事务
   
16.4 事务
事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性
原子性(atomicity)。一个事务是一个不可分割的工作单位,事务中包括的操作要么都做,要么都不做。
一致性(consistency)。事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
隔离性(isolation)。一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
持久性(durability)。持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。
   
16.5 转账事务案例
-- 默认提交事务
begin;
commit; -- 提交事务
rollback; -- 事务回滚//代码里面默认回滚事务
connection.setAutoCommit(false); //不自动提交事务
connection.commit();//提交事务
connection.rollback();//回滚事务

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/220999.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络考研辨析(后续整理入笔记)

文章目录 体系结构物理层速率辨析交换方式辨析编码调制辨析 链路层链路层功能介质访问控制&#xff08;MAC&#xff09;信道划分控制之——CDMA随机访问控制轮询访问控制 扩展以太网交换机 网络层网络层功能IPv4协议IP地址IP数据报分析ICMP 网络拓扑与转发分析&#xff08;重点…

【Git】在 IDEA 中合并多个 commit 为一个

文章目录 1 未提交到远程分支1.1 需求说明1.2 reset 操作1.3 再次 push 2 已经提交到远程分支2.1 需求说明2.2 rebase 操作2.3 强制 push 分两种情况&#xff1a; 一种是本地提交还没推到远程&#xff0c;这种好处理另一种是已经提交到远程分支&#xff0c;这个略麻烦 1 未提…

我的4096创作纪念日

机缘 岁月如梭&#xff0c;时光一晃已经在CSDN扎根4096天了。第一次注册CSDN好像还是在2012年&#xff0c;那会还没大学毕业。初入CSDN&#xff0c;只是把他当作自己编程时遇到问题的在线笔记记录而已&#xff0c;没想到无意间还帮助了其他遇到同样问题困扰的同学。而在这4096…

杰发科技AC7840——SPM电源管理之低功耗模式

0、SPM简介 很早以前就听过低功耗模式&#xff0c;一直没有怎么深入了解&#xff0c;最近遇到几个项目都是跟低功耗有关。正好AutoChips的芯片都有电源管理的功能&#xff0c;在此借用AC7840的SPM对低功耗进行测试。 1、AC7840的5种功耗模式 2、AC7840的模式转换 3、唤醒 在…

Java实现一个在windows环境下的文件搜索引擎

以下是一个简单的Java实现的Windows文件搜索引擎的示例代码&#xff1a; import java.io.File; import java.util.ArrayList; import java.util.List;public class FileSearchEngine {public static void main(String[] args) {String searchDirectory "C:/"; // …

保护您的Android应用程序:Android应用程序安全一览

保护您的Android应用程序&#xff1a;Android应用程序安全一览 我们都知道Android是为所有人设计的——开放、面向开发者、面向用户&#xff0c;这种开放性为今天和明天的移动技术提供了很多便利。然而&#xff0c;开放性也带来了需要妥善处理的安全风险。 安全是我们所有人都…

lua语法

lua语法 1.lua数据类型 lua 脚本输出乱码&#xff0c;将lua脚本改为UTF-8编码&#xff0c;并且需要DOS下修改代码页&#xff1a;CHCP 65001 即可。 基本语法 注释 print("script lua win")-- 单行注释--[[多行注释]]--标识符 类似于&#xff1a;java当中 变量、…

【论文笔记】动态蛇卷积(Dynamic Snake Convolution)

精确分割拓扑管状结构例如血管和道路&#xff0c;对医疗各个领域至关重要&#xff0c;可确保下游任务的准确性和效率。然而许多因素使分割任务变得复杂&#xff0c;包括细小脆弱的局部结构和复杂多变的全局形态。针对这个问题&#xff0c;作者提出了动态蛇卷积&#xff0c;该结…

随笔记录-springboot_LoggingApplicationListener+LogbackLoggingSystem

环境&#xff1a;springboot-2.3.1 加载日志监听器初始化日志框架 SpringApplication#prepareEnvironment SpringApplicationRunListeners#environmentPrepared EventPublishingRunListener#environmentPrepared SimpleApplicationEventMulticaster#multicastEvent(Applicati…

MapReduce和Yarn部署+入门

看的黑马视频记的笔记 目录 1.入门知识点 分布式计算&#xff1a; 概念&#xff1a; 两种模式&#xff1a; MapReduce&#xff08;分布式计算&#xff0c;分散汇总模式&#xff09; 概念 执行原理 注&#xff1a; Yarn&#xff08;分布式资源调度&#xff09; 概述 Y…

【大模型AIGC系列课程 5-2】视觉-语言大模型原理

重磅推荐专栏: 《大模型AIGC》;《课程大纲》 本专栏致力于探索和讨论当今最前沿的技术趋势和应用领域,包括但不限于ChatGPT和Stable Diffusion等。我们将深入研究大型模型的开发和应用,以及与之相关的人工智能生成内容(AIGC)技术。通过深入的技术解析和实践经验分享,旨在…

全链路压力测试:解析其主要特点

随着信息技术的飞速发展和云计算的普及&#xff0c;全链路压力测试作为一种关键的质量保障手段&#xff0c;在软件开发和系统部署中扮演着至关重要的角色。全链路压力测试以模拟真实生产环境的压力和负载&#xff0c;对整个业务流程进行全面测试&#xff0c;具有以下主要特点&a…

【IDEA】Intellij IDEA相关配置

IDEA 全称 IntelliJ IDEA&#xff0c;是java编程语言的集成开发环境。IntelliJ在业界被公认为最好的Java开发工具&#xff0c;尤其在智能代码助手、代码自动提示、重构、JavaEE支持、各类版本工具(git、svn等)、JUnit、CVS整合、代码分析、 创新的GUI设计等方面的功能可以说是超…

pytorch中nn.Sequential详解

1 nn.Sequential概述 1.1 nn.Sequential介绍 nn.Sequential是一个序列容器&#xff0c;用于搭建神经网络的模块被按照被传入构造器的顺序添加到容器中。除此之外&#xff0c;一个包含神经网络模块的OrderedDict也可以被传入nn.Sequential()容器中。利用nn.Sequential()搭建好…

关于“Python”的核心知识点整理大全26

目录 10.3.9 决定报告哪些错误 10.4 存储数据 10.4.1 使用 json.dump()和 json.load() number_writer.py number_reader.py 10.4.2 保存和读取用户生成的数据 对于用户生成的数据&#xff0c;使用json保存它们大有裨益&#xff0c;因为如果不以某种方式进行存储&#xf…

介绍Silabs一款zigbee芯片:MG21

1.1 EFR32MG21系列&#xff0c;这款芯片旨在高性能、低功耗、安全解决方案&#xff0c;符合IEEE802.15.4规范和ZigBee3.0协议标准&#xff0c;采用2.4G SoC&#xff0c;适用于ZigBee、Thread等应用 &#xff0c;96K的RAM数据存储器及高达1024k的闪存程序存储器. 1.2 典型应用…

HarmonyOS应用开发-手写板(二)

在前一篇手写板的文章中&#xff08;HarmonyOS应用开发-手写板-CSDN博客&#xff09;&#xff0c;我们通过使用Path实现了一个基本的手写板&#xff0c;但遗憾的是&#xff0c;无法保存所绘制的图像。在本文中&#xff0c;我们将采用canvas和Path2D来重新构建手写板应用。依然只…

新手上路:自动驾驶行业快速上手指南

文章目录 1.自动驾驶技术的发展1.1 工业革命驱动自动驾驶技术发展1.2 想象中的未来&#xff1a;科幻作品中的自动驾驶汽车1.3 自动驾驶技术萌芽与尝试1.4 百花争鸣&#xff1a;自动驾驶科技巨头与创业公司并进 2.个人开发者&#xff0c;如何玩转自动驾驶&#xff1f;2.1 灵活易…

MySQL数据库,触发器、窗口函数、公用表表达式

触发器 触发器是由事件来触发某个操作&#xff08;也包含INSERT、UPDATE、DELECT事件&#xff09;&#xff0c;如果定义了触发程序&#xff0c;当数据库执行这些语句时&#xff0c;就相当于事件发生了&#xff0c;就会自动激发触发器执行相应的操作。 当对数据表中的数据执行…

02.Git常用基本操作

一、基本配置 &#xff08;1&#xff09;打开Git Bash &#xff08;2&#xff09;配置姓名和邮箱 git config --global user.name "Your Name" git config --global user.email "Your email" 因为Git是分布式版本控制工具&#xff0c;所以每个用户都需要…