数据库连接JDBC
概述
✅概念
JDBC(JavaDataBaseConnectivityjava数据库连接)是⼀种⽤于执⾏SQL语句的JavaAPI,可以为多种关系型数据库提供
统⼀访问,它是由⼀组⽤Java语⾔编写的类和接⼝组成的。
本质
其实就是java官⽅提供的⼀套规范(接⼝)。⽤于帮助开发⼈员快速实现不同关系型数据库的连接!
功能详解
public class JDBCQuick {public static void main(String[] args) throws Exception {//1.注册驱动(可省略)// Class.forName("com.mysql.cj.jdbc.Driver");// DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());//2.获取连接对象String url = "jdbc:mysql://localhost:3306/itcast";String user = "root";String password = "20050606a";Connection connection = DriverManager.getConnection(url, user, password);//3.获取执⾏SQL语句的对象Statement statement = connection.createStatement();System.out.println("请输⼊员⼯的姓名:");Scanner scanner = new Scanner(System.in);String name1 = scanner.nextLine();//4.编写SQL语句,并执⾏,接受返回的结果集String sql = "select * from employee where name='"+name1+"'";ResultSet resultSet = statement.executeQuery(sql);//5.处理结果遍历resultSet结果集while (resultSet.next()) {int id = resultSet.getInt("id");String workno= resultSet.getString("workno");String name = resultSet.getString("name");String gender = resultSet.getString("gender");int age = resultSet.getInt("age");String idcard = resultSet.getString("idcard");Date entrydate = resultSet.getDate("entrydate");String workaddress = resultSet.getString("workaddress");System.out.println(id+"\t"+workno+"\t"+name+"\t"+gender+"\t"+age+"\t"+idcard+"\t"+entrydate+"\t"+workaddress);}//6.释放资源(先开后关)resultSet.close();statement.close();connection.close();}}
public class JDBCPrepareStatement {public static void main(String[] args) throws Exception {//1.
注册驱动
(
可省略)// Class.forName("com.mysql.cj.jdbc.Driver");// DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());//2.获取连接对象String url = "jdbc:mysql://localhost:3306/itcast";String user = "root";String password = "20050606a";Connection connection = DriverManager.getConnection(url, user, password);//3.获取执⾏SQL语句的对象,防⽌SQL注⼊PreparedStatement preparedStatement = connection.prepareStatement("select * from employee where name=?");System.out.println("请输⼊员⼯的姓名:");Scanner scanner = new Scanner(System.in);String name1 = scanner.nextLine();//4.为?占位符赋值,并执⾏SQL语句,接受返回的结果集preparedStatement.setString(1, name1);ResultSet resultSet = preparedStatement.executeQuery();//5.处理结果遍历resultSet结果集while (resultSet.next()) {int id = resultSet.getInt("id");String workno= resultSet.getString("workno");String name = resultSet.getString("name");String gender = resultSet.getString("gender");int age = resultSet.getInt("age");String idcard = resultSet.getString("idcard");Date entrydate = resultSet.getDate("entrydate");String workaddress = resultSet.getString("workaddress");System.out.println(id+"\t"+workno+"\t"+name+"\t"+gender+"\t"+age+"\t"+idcard+"\t"+entrydate+"\t"+workaddress);}//6.释放资源(先开后关)resultSet.close();preparedStatement.close();connection.close();}}
DriverManager驱动管理对象
✅(1)注册驱动:(mysql5以后可直接省略驱动)
1.注册给定的驱动程序:staticvoidregisterDriver(Driverdriver);
2.写代码使⽤:Class.forName(“com.mysql.jdbc.Driver”);
3.在com.mysql.jdbc.Driver类中存在静态代码块
(2)获取数据库连接:
1.获取数据库连接对象:staticConnectiongetConnection(Stringurl,Stringuser,Stringpassword)
2.返回值:Connection数据库连接对象
3.参数
url:指定连接的路径。语法:jdbc:mysql://ip地址(域名):端⼝号/数据库名称
user:⽤⼾名
password:密码
Connection数据库连接对象
✅1.获取执⾏者对象:
获取普通执⾏者对象:StatementcreateStatement0;
获取预编译执⾏者对象:PreparedStatementprepareStatement(Stringsql);
2.管理事务
开启事务:setAutoCommit(booleanautoCommit);参数为false,则开启事务
提交事务:commit();
回滚事务:rollback();
3.释放资源
⽴即将数据库连接对象释放:voidclose();
Statement执⾏sql语句的对象
✅(1)执⾏DML语句:intexecuteUpdate(Stringsql);
返回值int:返回影响的⾏数。
参数sql:可以执⾏insert、update、delete语句。
(2) 执⾏DQL语句:ResultSetexecuteQuery(Stringsql);
返回值ResultSet:封装查询的结果。
参数sql:可以执⾏select语句。
(3)释放资源
⽴即将数据库连接对象释放:voidclose();
ResultSet结果集对象
✅1.判断结果集中是否还有数据:booleannext();
有数据返回true,并将索引向下移动⼀⾏。没有数据返回false。
2.获取结果集中的数据:XXXgetXxx(“列名”);XXX代表数据类型(要获取某列数据,这⼀列的数据类型)。
例如:StringgetString(“name”);
int getInt(" age");
3.释放资源
⽴即将结果集对象释放:voidclose();
ORM
ORM是⼀种思想,ORM(全称为:ObjectRelativeMapping)对象-关系映射
关系数据库是企业级应⽤环境中永久存放数据的主流数据存储系统。对象和关系数据是业务实体的两种表现形式,业务实
体在内存中表现为对象,在数据库中表现为关系数据。内存中的对象之间存在关联和继承关系,⽽在数据库中,关系数据
⽆法直接表达多对多关联和继承关系。因此,对象-关系映射(ORM)系统⼀般以中间件的形式存在,主要实现程序对象到关
系数据库数据的映射。
ORM模型的简单性简化了数据库查询过程。使⽤ORM查询⼯具,⽤⼾可以访问期望数据,⽽不必理解数据库的底层结构。
- 在使⽤JDBC操作数据库时,我们会发现数据都是零散的,明明在数据库中是⼀⾏完整的数据,到了Java中变成了⼀
个⼀个的变量,不利于维护和管理。⽽我们Java是⾯向对象的,⼀个表对应的是⼀个类,⼀⾏数据就对应的是Java
中的⼀个对象,⼀个列对应的是对象的属性,所以我们要把数据存储在⼀个载体⾥,这个载体就是实体类! - ORM(ObjectRelationalMapping)思想,对象到关系数据库的映射,作⽤是在编程中,把⾯向对象的概念
跟数据库中表的概念对应起来,以⾯向对象的⻆度操作数据库中的数据,即⼀张表对应⼀个类,⼀⾏数据对应⼀个对 象,⼀个列对应⼀个属性! - 当下JDBC中这种过程我们称其为⼿动ORM。后续我们也会学习ORM框架,⽐如MyBatis、JPA等。
public class Student {private Integer stuID;//stu_idprivate String stuName;//sut_nameprivate Integer stuAge;//stu_agepublic Student() {}public Student(String stuName, Integer stuID, Integer stuAge) {this.stuName = stuName;this.stuID = stuID;this.stuAge = stuAge;}@Overridepublic String toString() {return "Student{" +"stuID=" + stuID +", stuName='" + stuName + '\'' +", stuAge=" + stuAge +'}';}public Integer getStuID() {return stuID;}public void setStuID(Integer stuID) {this.stuID = stuID;}public String getStuName() {return stuName;}public void setStuName(String stuName) {this.stuName = stuName;}public Integer getStuAge() {return stuAge;}public void setStuAge(Integer stuAge) {this.stuAge = stuAge;}}
public class JDBCAdvanced {@Testpublic void testORM() throws SQLException {Connection connection = DriverManager.getConnection("jdbc:mysql:///itcast", "root", "20050606a");PreparedStatement preparedStatement = connection.prepareStatement("select * from t_stu where stu_id=?");preparedStatement.setInt(1, 1);ResultSet resultSet = preparedStatement.executeQuery();Student student = null;if(resultSet.next()) {int stuId = resultSet.getInt("stu_id");String stuName = resultSet.getString("stu_name");int stuAge = resultSet.getInt("stu_age");//为对象的属性赋值student=new Student();student.setStuID(stuId);student.setStuName(stuName);student.setStuAge(stuAge);}System.out.println(student);resultSet.close();preparedStatement.close();connection.close();}@Testpublic void testORMList() throws Exception {Connection connection = DriverManager.getConnection("jdbc:mysql:///itcast", "root", "20050606a");PreparedStatement preparedStatement = connection.prepareStatement("select * from t_stu ");ResultSet resultSet = preparedStatement.executeQuery();Student student = null;List<Student> list = new ArrayList<Student>();while(resultSet.next()) {student = new Student();int stuId = resultSet.getInt("stu_id")String stuName = resultSet.getString("stu_name");int stuAge = resultSet.getInt("stu_age");//为对象的属性赋值student=new Student();student.setStuID(stuId);student.setStuName(stuName);student.setStuAge(stuAge);list.add(student);}for(Student stu:list){System.out.println(stu);}resultSet.close();preparedStatement.close();connection.close();}}
主键回显
✅-在数据中,执⾏新增操作时,主键列为⾃动增⻓,可以在表中直观的看到,但是在Java程序中,我们执⾏完新增后,只
能得到受影响⾏数,⽆法得知当前新增数据的主键值。在Java程序中获取数据库中插⼊新数据后的主键值,并赋值给Java
对象,此操作为主键回显。
public void testReturnPK() throws SQLException {//获取连接Connection connection = DriverManager.getConnection("jdbc:mysql:///itcast", "root", "20050606a");//预编译SQL语句,告知prapareStatement,返回新增数据的主键列的值String sql = "insert t_stu (stu_name,stu_age) values(?,?);";PreparedStatement preparedStatement = connection.prepareStatement(sql,
Statement.RETURN_GENERATED_KEYS);//创建对象,将对象的属性值,填充到?占位符上(ORM)Student student = new Student("Bob", null, 21);preparedStatement.setString(1, student.getStuName());preparedStatement.setInt(2, student.getStuAge());//执⾏SQL语句,并获取返回的结果int i = preparedStatement.executeUpdate();//处理结果ResultSet resultSet = null;if (i > 0) {System.out.println("成功");//获取新增的主键列,回显到Student对象的stuId属性上//返回主键的值,是⼀个单⾏单列的值储存再resultSet⾥resultSet = preparedStatement.getGeneratedKeys();if (resultSet.next()) {int stuId = resultSet.getInt(1);student.setStuID(stuId);}System.out.println(student);} else {System.out.println("失败");}//关闭资if (resultSet != null) {resultSet.close();}preparedStatement.close();connection.close();}
批量操作
插⼊多条数据时,⼀条⼀条发送给数据库执⾏,效率低下!
通过批量操作,可以提升多次操作效率!
注意:1、必须在连接数据库的URL后⾯追加?rewriteBatchedStatements=true,允许批量操作
2、新增SQL必须⽤values。且语句最后不要追加;结束
3、调⽤addBatch()⽅法,将SQL语句进⾏批量添加操作
4、统⼀执⾏批量操作,调⽤executeBatch()
@Testpublic void testBatch() throws SQLException {//批量操作Connection connection = DriverManager.getConnection("jdbc:mysql:///itcast?rewriteBatchedStatements=true", "root", "20050606a");//预编译SQL语句,告知prapareStatement,返回新增数据的主键列的值//必须是values,不能加分号String sql = "insert t_stu (stu_name,stu_age) values(?,?)";PreparedStatement preparedStatement = connection.prepareStatement(sql);long start = System.currentTimeMillis();for(int i=1;i<=10000;i++){preparedStatement.setString(1, "name"+i);preparedStatement.setInt(2, 1+i);//使⽤addBatch() preparedStatement.addBatch();}//执⾏批量操作preparedStatement.executeBatch();long end = System.currentTimeMillis();System.out.println("消耗的时间"+(end-start));preparedStatement.close();connection.close();}
SQL注⼊
原理
✅
- sql注⼊攻击:就是利⽤sql语句的漏洞来对系统进⾏攻击
- 按照正常道理来说,我们在密码处输⼊的所有内容,都应该认为是密码的组成
- 但是现在Statement对象在执⾏sql语句时,将⼀部分内容当做查询条件来执⾏了
PreparedStatement的介绍
✅预编译sql语句的执⾏者对象。在执⾏sql语句之前,将sql语句进⾏提前编译
明确sql语句的格式后,就不会改变了。剩余的内容都会认为是参数
参数使⽤?作为占位符
为参数赋值的⽅法:setXxx(参数1,参数2);
参数1:?的位置编号(编号从1开始)
参数2:?的实际参数
执⾏sql语句的⽅法
执⾏insert、update、delete语句:intexecuteUpdate();
执⾏select语句:ResultSetexecuteQuery();
/*使⽤
PreparedStatement
的登录⽅法,解决注⼊攻击*/@Overridepublic User findByLoginNameAndPassword(String loginName, String password) {//定义必要信息Connection conn = null;PreparedStatement pstm = null;ResultSet rs = null;User user = null;try {//1.获取连接conn = JDBCUtils.getConnection();//2.创建操作SQL对象String sql = "SELECT * FROM user WHERE loginname=? AND password=?";pstm = conn.prepareStatement(sql);//3.设置参数pstm.setString(1,loginName);//设置第⼀个?参数pstm.setString(2,password);//设置第⼆个?参数System.out.println(sql);//4.执⾏sql语句,获取结果集rs = pstm.executeQuery();//5.获取结果集if (rs.next()) {//6.封装user = new User();user.setUid(rs.getString("uid"));user.setUcode(rs.getString("ucode"));user.setUsername(rs.getString("username"));user.setPassword(rs.getString("password"));user.setGender(rs.getString("gender"));user.setDutydate(rs.getDate("dutydate"));user.setBirthday(rs.getDate("birthday"));user.setLoginname(rs.getString("loginname"));}//7.返回return user;}catch (Exception e){throw new RuntimeException(e);}finally {JDBCUtils.close(conn,pstm,rs);}}
连接池
概念
✅数据库连接背景
数据库连接是⼀种关键的、有限的、昂贵的资源,这⼀点在多⽤⼾的⽹⻚应⽤程序中体现得尤为突出
对数据库连接的管理能显著影响到整个应⽤程序的伸缩性和健壮性,影响到程序的性能指标
数据库连接池正是针对这个问题提出来的
数据库连接池
数据库连接池负责分配、管理和释放数据库连接
它允许应⽤程序重复使⽤⼀个现有的数据库连接,⽽不是再重新建⽴⼀个
这项技术能明显提⾼对数据库操作的性能
数据库连接池原理
之前的程序:来⼀个访问就会创建⼀个连接,使⽤完了关闭连接。频繁的创建连接和关闭连接是⾮常耗时的。
优化后的程序:提前准备⼀些数据库连接,使⽤的时候从池中获取,⽤完后重新归还给池中。
连接池就是数据库连接对象的缓冲区,通过配置,由连接池负责创建连接、管理连接、释放连接等操作。
预先创建数据库连接放⼊连接池,⽤⼾在请求时,通过池直接获取连接,使⽤完毕后,将连接放回池中,避免了频繁的
创建和销毁,同时解决了创建的效率。
当池中⽆连接可⽤,且未达到上限时,连接池会新建连接。
池中连接达到上限,⽤⼾请求会等待,可以设置超时时间。
常⻅连接池
JDBC的数据库连接池使⽤javax.sql.DataSource接⼝进⾏规范,所有的第三⽅连接池都实现此接⼝,⾃⾏添加具体实
现!也就是说,所有连接池获取连接的和回收连接⽅法都⼀样,不同的只有性能和扩展功能!
- DBCP是Apache提供的数据库连接池,速度相对C3P0较快,但⾃⾝存在⼀些BUG。
- C3P0是⼀个开源组织提供的⼀个数据库连接池,速度相对较慢,稳定性还可以。
- Proxool 是sourceforge下的⼀个开源项⽬数据库连接池,有监控连接池状态的功能,稳定性较c3p0差⼀点
- Druid 是阿⾥提供的数据库连接池,是集DBCP、C3P0、Proxool优点于⼀⾝的数据库连接池,性能、扩展性、易⽤
性都更好,功能丰富。 - Hikari(ひかり[shigali])取⾃⽇语,是光的意思,是SpringBoot2.x之后内置的⼀款连接池,基于BoneCP(已经
放弃维护,推荐该连接池)做了不少的改进和优化,⼝号是快速、简单、可靠。
Druid
硬编码
public void testDruidHardTest() throws SQLException {/* 硬编码:将连接池的配置信息和Java代码耦合在⼀起。1、创建HikariDataSource连接池对象2、设置连接池的配置信息【必须|⾮必须】3、通过连接池获取连接对象4、回收连接
*/
DruidDataSource druidDataSource = new DruidDataSource();//必须设置的配置druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");druidDataSource.setUrl("jdbc:mysql:///itcast");druidDataSource.setUsername("root");druidDataSource.setPassword("20050606a");//⾮必须设置的配置//基于connection的增删改查druidDataSource.setInitialSize(10);druidDataSource.setMaxActive(20);DruidPooledConnection connection = druidDataSource.getConnection();System.out.println(connection);connection.close();}
软编码
✅db.properties
driverClassName=com.mysql.cj.jdbc.Driverurl=jdbc:mysql:///itcastusername=rootpassword=20050606ainitialSize=10maxActive=20
public void test() throws Exception {//1.创建Properties集合,⽤于存储外部配置⽂件的key和value值。Properties properties = new Properties();//2.读取外部配置⽂件,获取输⼊流,加载到Properties集合⾥。InputStream inputStream = DruidTest.class.getClassLoader().getResourceAsStream("db.properties");properties.load(inputStream);//3.基于Properties集合构建DruidDataSource连接池DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);//4.通过连接池获取连接对象Connection connection = dataSource.getConnection();System.out.println(connection);//5.开发CRUD
//6.回收连接connection.close();}
Hikari
硬编码
@Testpublic void testHardTestHikari() throws SQLException {/* 硬编码:将连接池的配置信息和Java代码耦合在⼀起。1、创建HikariDataSource连接池对象2、设置连接池的配置信息【必须|⾮必须】3、通过连接池获取连接对象4、回收连接
*/
//1.创建HikariDataSource连接池对象HikariDataSource hikariDataSource = new HikariDataSource();//2.设置连接池的配置信息【必须 | ⾮必须】//2.1必须设置的配置hikariDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");hikariDataSource.setJdbcUrl("jdbc:mysql:///itcast");hikariDataSource.setUsername("root");hikariDataSource.setPassword("20050606a");//2.2 ⾮必须设置的配置hikariDataSource.setMinimumIdle(10);hikariDataSource.setMaximumPoolSize(20);//3.通过连接池获取连接对象Connection connection = hikariDataSource.getConnection();System.out.println(connection);//回收连接connection.close();}
软编码
@Testpublic void testResourcesHikari() throws Exception {//1.创建Properties集合,⽤于存储外部配置⽂件的key和value值。Properties properties = new Properties();//2.读取外部配置⽂件,获取输⼊流,加载到Properties集合⾥。InputStream inputStream = HikariTest.class.getClassLoader().getResourceAsStream("hikari.properties");properties.load(inputStream);// 3.创建Hikari连接池配置对象,将Properties集合传进去HikariConfig hikariConfig = new HikariConfig(properties);// 4. 基于Hikari配置对象,构建连接池HikariDataSource hikariDataSource = new HikariDataSource(hikariConfig);
// 5.
获取连接Connection connection = hikariDataSource.getConnection();System.out.println("connection = " + connection);//6.
回收连接connection.close();}
JDBC优化及⼯具类的封装
JDBC⼯具类封装1.0
package senior.util;import com.alibaba.druid.pool.DruidDataSourceFactory;import javax.sql.DataSource;import java.io.IOException;import java.io.InputStream;import java.sql.Connection;import java.sql.SQLException;import java.util.Properties;public class JDBCUtil {//创建连接池引⽤private static DataSource dataSource;static {try{Properties prop = new Properties();InputStream inputStream = JDBCUtil.class.getClassLoader().getResourceAsStream("db.properties");prop.load(inputStream);dataSource= DruidDataSourceFactory.createDataSource(prop);} catch (Exception e) {throw new RuntimeException(e);}}//对外提供在连接池中获取连接的⽅法public static Connection getConnection(){try{return dataSource.getConnection();}catch (SQLException e){throw new RuntimeException(e);}}//对外提供回收连接的⽅法public static void release(Connection connection){try {connection.close();} catch (SQLException e) {throw new RuntimeException(e);}}}
JDBC⼯具类封装2.0
package senior.util;import com.alibaba.druid.pool.DruidDataSourceFactory;import javax.sql.DataSource;import java.io.InputStream;import java.sql.Connection;import java.sql.SQLException;import java.util.Properties;public class JDBCUtilV2 {//维护⼀个连接池对象,维护了⼀个线程绑定变量的ThreadLocal对象private static DataSource dataSource;private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();static {try{Properties prop = new Properties();InputStream inputStream = JDBCUtilV2.class.getClassLoader().getResourceAsStream("db.properties");prop.load(inputStream);dataSource= DruidDataSourceFactory.createDataSource(prop);} catch (Exception e) {throw new RuntimeException(e);}}//对外提供在ThreadLocal中获取连接对象的⽅法public static Connection getConnection(){try{//在ThreadLocal中获取connection Connection connection= threadLocal.get();if(connection==null){connection= dataSource.getConnection();threadLocal.set(connection);}return connection;}catch (SQLException e){throw new RuntimeException(e);}}//对外提供回收连接的⽅法,回收过程中,将回收的连接从ThreadLocal中移除!public static void release(){try {Connection connection = threadLocal.get();if(connection!=null){threadLocal.remove();connection.close();}} catch (SQLException e) {throw new RuntimeException(e);}}
Dao封装及DaoBase⼯具类
DaseDAO
package senior.dao;import senior.util.JDBCUtil;import senior.util.JDBCUtilV2;import java.lang.reflect.Field;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.ResultSetMetaData;import java.util.ArrayList;import java.util.List;public class BaseDAO {//通⽤的增删改⽅法public int executeUpdate(String sql,Object...params) throws Exception {Connection connection= JDBCUtilV2.getConnection();PreparedStatement preparedStatement = connection.prepareStatement(sql);if(params!=null&¶ms.length>0){for(int i=0;i<params.length;i++){preparedStatement.setObject(i+1,params[i]);}}int updateCount = preparedStatement.executeUpdate();preparedStatement.close();JDBCUtilV2.release();return updateCount;}//通⽤的查询⽅法public <T> List<T> executeQuery(Class<T> clazz,String sql,Object...params) throws Exception {Connection connection= JDBCUtilV2.getConnection();PreparedStatement preparedStatement = connection.prepareStatement(sql);if(params!=null&¶ms.length>0){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<>();while(resultSet.next()){//循环⼀次通过反射创建⼀个对象T t = clazz.newInstance();for(int i=1;i<=columnCount;i++){Object value = resultSet.getObject(i);//获取列的名字=对象的属性String filedName = metaData.getColumnLabel(i);//通过对象和filedName获取要封装的属性Field field = clazz.getDeclaredField(filedName);field.setAccessible(true);field.set(t,value);}list.add(t);}resultSet.close();preparedStatement.close();JDBCUtilV2.release();return list;}//通⽤的查询单个结果的⽅法public <T> T executeQueryBean(Class<T> clazz,String sql,Object...params) throws Exception {List<T> list=this.executeQuery(clazz,sql,params);if(!list.isEmpty()){return null;}return list.get(0);}}
StudentDao
package senior.dao;import senior.pojo.Student;import java.util.List;public interface StudentDao {List<Student> selectAllStudents();Student selectStudentById(int id);int insertStudent(Student student);int updateStudent(Student student);int deleteStudent(int id);}
StudentDaoImpl
package senior.dao;import senior.pojo.Student;import java.util.List;public class StudentDaoImpl extends BaseDAO implements StudentDao{@Overridepublic List<Student> selectAllStudents() {String sql="SELECT stu_id stuID ,stu_name stuName,stu_age stuAge from itcast.t_stu";try {return executeQuery(Student.class,sql,null);} catch (Exception e) {throw new RuntimeException(e);}}@Overridepublic Student selectStudentById(int id) {String sql="SELECT stu_id stuID ,stu_name stuName,stu_age stuAge from itcast.t_stu where stu_id=?";try {return executeQueryBean(Student.class,sql,id);} catch (Exception e) {throw new RuntimeException(e);}}@Overridepublic int insertStudent(Student student) {String sql="INSERT INTO itcast.t_stu (stu_name, stu_age) values (?,?)";try {return executeUpdate(sql,student.getStuName(),student.getStuAge());} catch (Exception e) {throw new RuntimeException(e);}}@Overridepublic int updateStudent(Student student) {String sql="Update itcast.t_stu SET stu_name =? where stu_age=?";try {return executeUpdate(sql,student.getStuName(),student.getStuAge());} catch (Exception e) {throw new RuntimeException(e);}}@Overridepublic int deleteStudent(int id) {String sql="DELETE FROM itcast.t_stu WHERE stu_id=?";try {return executeUpdate(sql,id);} catch (Exception e) {throw new RuntimeException(e);}}}
事务
Show VARIABLES LIKE 'autocommit';SET autocommit =false;COMMIT ;ROLLBACK ;UPDATE t_bank SET money=money-100 WHERE id=1;UPDATE t_bank SET money=money+100 WHERE id=2;CREATE TABLE t_bank(id INT PRIMARY KEY AUTO_INCREMENT COMMENT '账号主键',account VARCHAR(20) NOT NULL UNIQUE COMMENT '账号',money INT UNSIGNED COMMENT '⾦额')COMMENT '银⾏账⼾';INSERT INTO t_bank(account, money) VALUES ('张三',1000);INSERT INTO t_bank(account, money) VALUES ('李四',1000);
package senior.dao;import senior.util.JDBCUtil;import senior.util.JDBCUtilV2;import java.lang.reflect.Field;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.ResultSetMetaData;import java.util.ArrayList;import java.util.List;public class BaseDAO {//通⽤的增删改⽅法public int executeUpdate(String sql,Object...params) throws Exception {Connection connection= JDBCUtilV2.getConnection();PreparedStatement preparedStatement = connection.prepareStatement(sql);if(params!=null&¶ms.length>0){for(int i=0;i<params.length;i++){preparedStatement.setObject(i+1,params[i]);}}int updateCount = preparedStatement.executeUpdate();preparedStatement.close();if(connection.getAutoCommit()){JDBCUtilV2.release();}return updateCount;}//通⽤的查询⽅法public <T> List<T> executeQuery(Class<T> clazz,String sql,Object...params) throws Exception {Connection connection= JDBCUtilV2.getConnection();PreparedStatement preparedStatement = connection.prepareStatement(sql);if(params!=null&¶ms.length>0){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<>();while(resultSet.next()){//循环⼀次通过反射创建⼀个对象T t = clazz.newInstance();for(int i=1;i<=columnCount;i++){Object value = resultSet.getObject(i);//获取列的名字=对象的属性String filedName = metaData.getColumnLabel(i);//通过对象和filedName获取要封装的属性Field field = clazz.getDeclaredField(filedName);field.setAccessible(true);field.set(t,value);}list.add(t);}resultSet.close();preparedStatement.close();if(connection.getAutoCommit()){JDBCUtilV2.release();}return list;}//通⽤的查询单个结果的⽅法public <T> T executeQueryBean(Class<T> clazz,String sql,Object...params) throws Exception {List<T> list=this.executeQuery(clazz,sql,params);if(!list.isEmpty()){return null;}return list.get(0);}}
package senior.util;import com.alibaba.druid.pool.DruidDataSourceFactory;import javax.sql.DataSource;import java.io.InputStream;import java.sql.Connection;import java.sql.SQLException;import java.util.Properties;public class JDBCUtilV2 {//维护⼀个连接池对象,维护了⼀个线程绑定变量的ThreadLocal对象private static DataSource dataSource;private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();static {try{Properties prop = new Properties();InputStream inputStream = JDBCUtilV2.class.getClassLoader().getResourceAsStream("db.properties");prop.load(inputStream);dataSource= DruidDataSourceFactory.createDataSource(prop);} catch (Exception e) {throw new RuntimeException(e);}}//对外提供在ThreadLocal中获取连接对象的⽅法public static Connection getConnection(){try{//在ThreadLocal中获取connection Connection connection= threadLocal.get();if(connection==null){connection= dataSource.getConnection();threadLocal.set(connection);}return connection;}catch (SQLException e){throw new RuntimeException(e);}}//对外提供回收连接的⽅法,回收过程中,将回收的连接从ThreadLocal中移除!public static void release(){try {Connection connection = threadLocal.get();if(connection!=null){threadLocal.remove();connection.setAutoCommit(true);connection.close();}} catch (SQLException e) {throw new RuntimeException(e);}}}
相关文章:
数据库连接JDBC
概述 ✅概念 JDBC(JavaDataBaseConnectivityjava数据库连接)是⼀种⽤于执⾏SQL语句的JavaAPI,可以为多种关系型数据库提供 统⼀访问,它是由⼀组⽤Java语⾔编写的类和接⼝组成的。 本质 其实就是java官⽅提供的⼀套规范(接⼝)。⽤于帮助开发⼈员快速实现…...
VectorBT:使用PyTorch+Transformer训练和回测股票模型 进阶五
VectorBT:使用PyTorchTransformer训练和回测股票模型 进阶五 本方案基于PyTorch框架与Transformer模型,结合VectorBT回测引擎构建多股票量化交易系统,采用滑动窗口技术构建时序特征,通过自注意力机制捕捉市场规律预测收益率&#…...
DP Alt Mode 与 USB 的关系
DP Alt Mode 与 USB 的关系 1. 物理接口的统一:USB-C 是“万能插座” [USB-C接口物理结构] |-----------------------------------------------| | USB 3.0数据引脚 | DP Alt Mode视频引脚 | 电源引脚 | |-------------------------------------…...
C#“与AI的奇妙结合”
原文:C# 使用通义灵码 - AI 助力 Visual Studio 开发_w3cschool (注意:本文章中并不存在任何广告,也不存在任何盈利内容) C# 使用通义灵码 C# 作为一种功能强大且灵活多变的编程语言,被广泛应用于各个领…...
企业ITR流程设计与执行详细介绍【附全文阅读】
该方案聚焦企业 ITR 流程,适用于企业的服务管理人员、流程优化负责人、技术支持团队以及中高层管理者等。 ITR 流程的重要性:企业服务面临客户不满、管理者焦虑、服务人员无奈等挑战,缺乏完善的 ITR 流程会影响品牌形象、客户满意度和产品竞争力。ITR 流程能够保障客户满意,…...
Ubuntu 无密码热点(Soft AP)完整配置方案
适用于 Jetson、嵌入式 Linux、RDK 平台。目标:配置一个无密码热点(Soft AP),供手机等设备直接连接。实现开机自动启动热点,也支持后续一键切换回 WiFi 客户端模式。 平台:Yahboom RDK X3(Jetso…...
【力扣hot100题】(063)搜索二维矩阵
看到这题我就想到之前被我当作这题做的【力扣hot100题】(020)搜索二维矩阵Ⅱ 其实是完全不一样的两题,个人觉得这道题更简单也更考验基础,那道题思路更难想到但代码更好写。 两个二分查找结束,要注意的是第一个二分查…...
瑞萨RA4M2使用心得-KEIL5的第一次编译
目录 前言 环境: 开发板:RA-Eco-RA4M2-100PIN-V1.0 IDE:keil5.35 一、软件的下载 编辑瑞萨的芯片,除了keil5 外还需要一个软件:RASC 路径:Releases renesas/fsp (github.com) 向下找到: …...
玄机-apache日志分析
靶场任务 1、提交当天访问次数最多的IP,即黑客IP: 查看apache日志 apache访问日志的位置是:/var/log/apache2/access.log.1 匹配正则算法 首先先cat看看 发现地址都在第一行,直接匹配计算输出 cat access.log.1 |grep -Eo &…...
[C++]洛谷B2119 删除单词后缀
题目与解析 题干题目描述输入格式输出格式样例样例输入样例输出 答案解析食用提示AC代码AC代码详细解析头文件部分主程序8~12行代码 12行以后的代码 题干 题目描述 给定一个单词,如果该单词以 er、ly 或者 ing 后缀结尾,则删除该后缀(题目保…...
Ubuntu远程连接Mysql数据库(图文详解)
Ubuntu远程连接Mysql数据库 1、版本2、检查有没有Mysql2.1 查询是否安装了Mysql包2.2 查看Mysql版本2.3 查看Mysql运行状态 3、卸载Mysql4、安装4.1 更新4.2 开始安装4.3 安装完后查看状态 5、登录5.1、使用5.2、查看数据库权限5.3 更新权限5.4 再次查看数据库权限5.5 添加新用…...
回归预测 | Matlab实现NRBO-Transformer-GRU多变量回归预测
回归预测 | Matlab实现NRBO-Transformer-GRU多变量回归预测 目录 回归预测 | Matlab实现NRBO-Transformer-GRU多变量回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.【JCR一区级】Matlab实现NRBO-Transformer-GRU多变量回归预测,牛顿-拉夫逊算法优…...
leetcode122-买卖股票的最佳时机II
leetcode 122 思路 方法一的核心思想是简单的贪心策略。我们每天都看当前价格和下一个价格的差值。如果下一个价格高于当前价格(即diff > 0),那么就认为当天可以买入并在第二天卖出,赚取利润。因此,方法一把所有…...
from PIL import Image 安装失败
正确安装 Pillow (PIL) # 通过 Conda 安装 conda install pillow -c conda-forge# 或通过 Pip 安装 pip install pillow验证安装 在 Python 中测试是否成功: from PIL import Image print(Image.__version__) # 应输出类似 "9.5.0" 的版本号常见问题说…...
DPFunc蛋白质功能预测模型复现报告
模型简介 模型的具体介绍见蛋白质功能预测论文阅读记录2025(DPFunc、ProtCLIP)_protein functions-CSDN博客 复现流程 仓库:CSUBioGroup/DPFunc 时间:2025.4.5 环境配置 python 3.9.21 & CUDA 11.6 Pytorch: 1.12.0 DG…...
在 Ubuntu24.04 LTS 上 Docker Compose 部署基于 Dify 重构二开的开源项目 Dify-Plus
一、安装环境信息说明 硬件资源(GB 和 GiB 的主要区别在于它们的换算基数不同,GB 使用十进制,GiB 使用二进制,导致相同数值下 GiB 表示的容量略大于 GB;换算关系:1 GiB ≈ 1.07374 GB ;1 GB ≈ …...
双系统ubuntu20.04不能外接显示器的解决办法
一,更换驱动 首先确定是不是英伟达显卡驱动,如果不是的话,设置里找到附加驱动,更改为NVIdia类型的驱动,更改完成之后重启 这里大部分电脑都可以了,如果不行 二、更改启动方式 重启之后进入BIOS设置&…...
高并发内存池:原理、设计与多线程性能优化实践
高并发内存池是一种专门为多线程环境设计的内存管理机制,其核心目标是通过优化内存分配和释放过程,解决传统内存分配器(如malloc/free)在高并发场景下的性能瓶颈,显著提升多线程程序的内存访问效率。 目录 一、核心设计…...
03.31-04.06 论文速递 聚焦具身智能、复杂场景渲染、电影级对话生成等五大前沿领域
🌟 论文速递 | 2025.03.31-04.06 📢 聚焦具身智能、复杂场景渲染、电影级对话生成等前沿领域 1️⃣ 具身智能体:从脑启发到安全协作系统 论文标题: Advances and Challenges in Foundation Agents: From Brain-Inspired Intellige…...
Django和Celery实现的异步任务案例
推荐超级课程: 本地离线DeepSeek AI方案部署实战教程【完全版】Docker快速入门到精通Kubernetes入门到大师通关课AWS云服务快速入门实战目录 先决条件步骤1:安装依赖项步骤2:配置Celery2.1 创建`celery.py`2.2 更新 `__init__.py`步骤3:配置Django设置步骤4:定义Celery任务…...
DAY 38 leetcode 15--哈希表.三数之和
题号15 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k ,同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。 未去重版本 整体思路:先排序再双指针遍…...
Java项目之基于ssm的个性化旅游攻略定制系统(源码+文档)
项目简介 个性化旅游攻略定制系统实现了以下功能: 个性化旅游攻略定制系统能够实现对用户上传信息,旅游路线信息,景点项目信息,景点信息,标签分类信息等信息的管理。 💕💕作者:落落…...
链表和数组的效率
访问元素 • 数组:通过索引直接访问元素,时间复杂度为O(1),速度很快。例如arr[5]可以立即访问到数组arr中索引为5的元素。 • 链表:需要从链表头开始逐个遍历节点,直到找到目标元素,平均时间复杂度为O(n)…...
经典回溯问题———组合的输出
题目如下 思路 代码如下...
WPS宏开发手册——附录
目录 系列文章7、附录 系列文章 使用、工程、模块介绍 JSA语法 JSA语法练习题 Excel常用Api Excel实战 常见问题 附录 7、附录 颜色序列:在excel中设置颜色,只能设置颜色序号,不能直接设置rgb颜色 1、黑色 (Black)…...
【leetcode100】买卖股票的最佳时机
1、题目描述 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从这笔交易中获取的最大利润。如果你…...
uniapp小程序登录失效后操作失灵问题
一开始我在请求返回失效验证时做了登录失效处理然后用uni.switchTab跳转主页的逻辑,结果发现在一天后重新打开小程序或者其他登录挤掉登录验证时有概率导致整个页面失灵无法操作。 经过排查发现,在小程序跳转新页面的时候如果遇到**(过快还是过多&#…...
找树左下角的值(DFS 深度优先搜索)| LeetCode 513
✨ 题目描述 给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。 提示: 二叉树中至少有一个节点。 📄 示例 示例 1 输入: root [2,1,3] 输出: 1示例 2 输入: [1,2,3,4,null,5,6,null,null,7] 输出: 7ǵ…...
【力扣hot100题】(060)分割回文串
每次需要判断回文串,这点比之前几题回溯题目复杂一些。 还有我怎么又多写了循环…… class Solution { public:vector<vector<string>> result;string s;bool palindromic(string s){for(int i0;i<s.size()/2;i) if(s[i]!s[s.size()-1-i]) return …...
中国钧瓷收藏市场现状和风险警示
一、数据权威性与综合维度 本榜单由钧瓷联合体、钧瓷频道及钧瓷数据库三方协同制作,通过10项规则综合评估匠人影响力,涵盖知名度、用户评价、平台指数等多元维度,避免单一指标(如拍卖价格)的片面性。榜单每月更新&…...
forms实现任务文档功能
说明: forms实现任务文档功能 效果图: step1:C:\Users\wangrusheng\RiderProjects\WinFormsApp26\WinFormsApp26\Form1.cs using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.IO; u…...
字符串的replace、replaceAll、split()方法
参考 字符串的replace、replaceAll、split()方法_字符串replace-CSDN博客...
Kotlin语言进阶:协程、Flow、Channel详解(二)
Kotlin语言进阶:协程、Flow、Channel详解(二) 一、Flow基础 1.1 什么是Flow Flow是Kotlin提供的用于处理异步数据流的解决方案,它建立在协程之上,具有以下特点: 冷流特性:只有在收集时才会开始发射数据背压处理:自动处理生产者和消费者速度不匹配的问题组合操作:提…...
VBA知识学习
文章目录 打开开发工具编写第一个VBA使用VBA调试器 VBA语法 打开开发工具 文件->选项->自定义功能区->开发工具 编写第一个VBA 点击开发工具 ->点击Visual Basic 选择sheet1->右键->插入->模块 Sub 第一个VBA程序()MsgBox "Hello World!&quo…...
JAVA EE_多线程-初阶(二)
1.线程安全 1.1.观察线程不安全 实例: package thread; public class text18 {//定义一个成员变量count,初始值为0private static int count0;public static void main(String[] args) throws InterruptedException {Thread t1new Thread(()->{for(int i0;i&l…...
【Linux】进程预备知识——冯诺依曼、操作系统
目录: 一、冯诺依曼体系结构 (一)什么是冯诺依曼 (二)为什么需要冯诺依曼 (三)冯诺依曼如何操作 二、操作系统概念 (一)对下硬件管理 (二)…...
Java入门首周精要:从基础语法到面向对象核心解析
文章目录 Java入门首周精要:从基础语法到面向对象核心解析1.Java类名与文件名的一致性规则2.Java和C语言中char类型的区别3.Java中的注释4.Java中的‘’‘’运算符5.Java的输入输出6.方法(重载&重写)方法的重载方法的重写 7.面向对象&…...
嵌入式AI开源生态指南:从框架到应用的全面解析
嵌入式AI开源生态指南:从框架到应用的全面解析 引言 随着人工智能技术的迅速发展,将AI能力部署到边缘设备上的需求日益增长。嵌入式AI通过在资源受限的微控制器上运行机器学习模型,实现了无需云连接的本地智能处理,大幅降低了延…...
MCP server的stdio和SSE分别是什么?
文章目录 一、Stdio:本地进程间通信的核心二、SSE:远程通信与实时推送的利器三、Stdio vs SSE:关键差异对比四、如何选择?场景驱动的决策指南五、实战建议与避坑指南实际操作结语在AI应用开发中,MCP(Model Context Protocol)协议正成为连接大模型与外部资源的核心桥梁。…...
哈希表(闭散列)的实现
目录 概念及定义 闭散列的介绍 闭散列底层实现 哈希表的定义 哈希表的构造 哈希表扩容 哈希表插入 哈希表删除 哈希表查找 概念及定义 哈希表,也成为散列表,在C中unordered_set和unordered_map的底层实现依靠的都是哈希表。 map和set的底层是红…...
Shiro学习(六):Shiro整合CAS实现单点登录
一、单点登录介绍 单点登录(Single Sign On),简称为 SSO,是比较流行的企业业务整合的解决方案之一。 SSO的定义是在多个[应用],用户只需要登录一次就可以访问所有相互信任的应用系统。 一般这种单点登录的实现方案&…...
HAProxy-ACL实战篇
HAProxy-ACL实战篇 IP说明172.25.254.101客户端172.25.254.102haproxy服务器172.25.254.103web1172.25.254.104web2 ACL示例-域名匹配 # 172.25.254.102 [rootRocky ~]# cat /etc/haproxy/conf.d/test.cfg frontend magedu_http_portbind 172.25.254.102:80mode httpbalanc…...
以下是针对该 Ansible 任务的格式检查和优化建议
以下是针对该 Ansible 任务的格式检查和优化建议: 目录 一、格式检查原始代码问题分析修正后的标准格式 二、推荐增强功能1. 添加可执行权限2. 显式指定 Shell 解释器3. 添加错误处理 三、完整 Playbook 示例四、验证脚本兼容性五、常见错误总结 一、格式检查 原始…...
C++语言的测试覆盖率
C语言的测试覆盖率分析与实践 引言 在软件开发过程中,测试覆盖率是一项重要的质量指标,它帮助开发者评估代码的测试效果,确保软件的可靠性与稳定性。尤其在C语言的开发中,由于其复杂的特性和丰富的功能,测试覆盖率的…...
如何使用 DrissionPage 进行网页自动化和爬取
在这个技术博客中,我们将向大家展示如何使用 DrissionPage 进行网页自动化操作与数据爬取。DrissionPage 是一个基于 Playwright 的 Python 自动化工具,它允许我们轻松地控制浏览器进行网页爬取、测试以及自动化操作。与其他工具(如 Selenium…...
设计模式 Day 3:抽象工厂模式(Abstract Factory Pattern)详解
经过前两天的学习,我们已经掌握了单例模式与工厂方法模式,理解了如何控制实例个数与如何通过子类封装对象的创建逻辑。 今天,我们将进一步深入“工厂”体系,学习抽象工厂模式(Abstract Factory Pattern)&a…...
TensorRT 有什么特殊之处
一、TensorRT的定义与核心功能 TensorRT是NVIDIA推出的高性能深度学习推理优化器和运行时库,专注于将训练好的模型在GPU上实现低延迟、高吞吐量的部署。其主要功能包括: 模型优化:通过算子融合(合并网络层)、消除冗余…...
SQL注入-盲注靶场实战(手写盲注payload)--SRC获得库名即可
布尔盲注 进入页面 注入点 ’ and 11 and 12 得知为布尔盲注 库名长度 and length(database()) 8 抓包(浏览器自动进行了url编码)爆破 得知为 12 库名字符 1 and ascii(substr(database(),1,1))112 – q (这里如果不再次抓包…...
http://noi.openjudge.cn/_2.5基本算法之搜索_1804:小游戏
文章目录 题目深搜代码宽搜代码深搜数据演示图总结 题目 1804:小游戏 总时间限制: 1000ms 内存限制: 65536kB 描述 一天早上,你起床的时候想:“我编程序这么牛,为什么不能靠这个赚点小钱呢?”因此你决定编写一个小游戏。 游戏在一…...
Windows Flip PDF Plus Corporate PDF翻页工具
软件介绍 Flip PDF Plus Corporate是一款功能强大的PDF翻页工具,也被称为名编辑电子杂志大师。这款软件能够迅速将PDF文件转换为具有翻页动画效果的电子书,同时保留原始的超链接和书签。无论是相册、视频、音频,还是Flash、视频和链接&#…...