大数据WEB阶段(七)JDBC、数据库批处理、数据库连接池
JDBC
一、概述
数据库驱动: 数据库厂商提供的用来操作数据库的jar包
- JDBC简介
- 由于各大数据库厂商提供的数据库驱动各不相同, 导致了开发人员的学习成本十分的高. SUN公司为了简化数据库的操作, 提供了一套规范, 本质上就是一大堆的接口, 要求各大数据库厂商在提供驱动时都要实现JDBC这套接口, 实现之后, 只要学会JDBC这套接口, 所有的数据库驱动就都会使用了!
- 六个步骤实现JDBC程序
在开发之前 , 首先要导入jar包
Connection conn = null; Statement stat = null; ResultSet rs = null; try {//1.注册数据库驱动Class.forName("com.mysql.jdbc.Driver");//2.获取数据库连接conn = DriverManager.getConnection("jdbc:mysql:///mydb5", "root", "root");//3.获取传输器stat = conn.createStatement();//4.利用传输器,发送sql到数据库执行,返回执行结果rs = stat.executeQuery("select * from account");//5.处理结果while(rs.next()){int id = rs.getInt(1);String name = rs.getString("name");double money = rs.getDouble("money");System.out.println(id+name+money);} } catch (Exception e) {e.printStackTrace();throw new RuntimeException(); }finally{//6.释放资源if(rs!=null){try {rs.close();} catch (SQLException e) {e.printStackTrace();}finally{rs = null;}}if(stat!=null){try {stat.close();} catch (SQLException e) {e.printStackTrace();}finally{stat = null;}}if(conn!=null){try {conn.close();} catch (SQLException e) {e.printStackTrace();}finally{conn = null;}} }
- JDBC API详解
- 注册数据库驱动
- 使用DriverManager.registerDriver(new Driver());注册数据库有两个缺点,首先,通过观察mysql的中Driver接口的实现类发现在静态代码块中注册驱动的逻辑,所以这种方式会造成驱动被注册两次。另外,这种方式导致了程序和具体的数据库驱动绑死在了一起,程序的灵活性比较低。
- 所以推荐使用:Class.forName(“com.mysql.jdbc.Driver”);的方式注册数据库驱动。
- 获取数据库连接 conn = DriverManager.getConnection(url,name,password);
数据库URL
URL用于标识数据库的位置,程序员通过URL地址告诉JDBC程序连接哪个数据库,URL的写法为:
jdbc:mysql://localhost:3306/test ?参数名=参数值
常用数据库URL地址的写法:
Oracle写法:jdbc:oracle:thin:@localhost:1521:sid SqlServer写法:jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=sid MySql:jdbc:mysql://localhost:3306/sid Mysql的url地址的简写形式: jdbc:mysql:///sid
Connection
Jdbc程序中的Connection,它用于代表数据库的链接,Connection是数据库编程中最重要的一个对象,客户端与数据库所有交互都是通过connection对象完成的,这个对象的常用方法:
createStatement():创建向数据库发送sql的statement对象。 prepareStatement(sql):创建向数据库发送预编译sql的PreparedSatement对象。 prepareCall(sql):创建执行存储过程的callableStatement对象。 setAutoCommit(boolean autoCommit):设置事务是否自动提交。 commit():在链接上提交事务。 rollback():在此链接上回滚事务。
Statement
Jdbc程序中的Statement对象用于向数据库发送SQL语句, Statement对象常用方法:
executeQuery(String sql) :用于向数据库发送查询语句。 executeUpdate(String sql):用于向数据库发送insert、update或delete语句 execute(String sql):用于向数据库发送任意sql语句 addBatch(String sql):把多条sql语句放到一个批处理中。 executeBatch():向数据库发送一批sql语句执行。
ResultSet
- Jdbc程序中的ResultSet用于代表Sql语句的执行结果。Resultset封装执行结果时,采用的类似于表格的方式。ResultSet 对象维护了一个指向表格数据行的游标,初始的时候,游标在第一行之前,调用ResultSet.next() 方法,可以使游标指向具体的数据行,进行调用方法获取该行的数据。
ResultSet既然用于封装执行结果的,所以该对象提供的都是用于获取数据的get方法:
获取任意类型的数据 getObject(int index) getObject(string columnName) 获取指定类型的数据,例如: getString(int index) getString(String columnName) getInt(columnIndex) getInt(columnLabel) getDouble(columnIndex) getDouble(columnLabel) ... 操作游标的方法,例如: next():移动到下一行 Previous():移动到前一行 absolute(int row):移动到指定行 beforeFirst():移动resultSet的最前面。 afterLast() :移动到resultSet的最后面。 ...
- 释放资源
- Jdbc程序运行完后,切记要释放程序在运行过程中,创建的那些与数据库进行交互的对象,这些对象通常是ResultSet, Statement和Connection对象。
- 特别是Connection对象,它是非常稀有的资源,用完后必须马上释放,如果Connection不能及时、正确的关闭,极易导致系统宕机。Connection的使用原则是尽量晚创建,尽量早的释放。
- 为确保资源释放代码能运行,资源释放代码也一定要放在finally语句中。
- JDBC的增删改查
增
//jdbc 增 public class Demo_01 {public static void main(String[] args) {Connection conn = null;Statement stat = null;ResultSet rs = null;try {//注册驱动Class.forName("com.mysql.jdbc.Driver");//获取连接conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/cszj","root","root");//获取传输器stat = conn.createStatement();//通过传输器将sql语句传输到mysql中int rows = stat.executeUpdate("insert into user values(7 ,'刘备','1234565')");//结果System.out.println("该操作影响了:"+rows+"行");} catch (Exception e) {e.printStackTrace();}finally{if(rs !=null){try {rs.close();} catch (SQLException e) {e.printStackTrace();}finally{rs = null;}}if(stat !=null){try {stat.close();} catch (SQLException e) {e.printStackTrace();}finally{stat = null;}}if(conn !=null){try {conn.close();} catch (SQLException e) {e.printStackTrace();}finally{conn = null;}}}} }
删
//jdbc 删 public class Demo_01 {public static void main(String[] args) {Connection conn = null;Statement stat = null;ResultSet rs = null;try {//注册驱动Class.forName("com.mysql.jdbc.Driver");//获取连接conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/cszj","root","root");//获取传输器stat = conn.createStatement();//通过传输器将sql语句传输到mysql中int rows = stat.executeUpdate("delete from user where id = 5");//结果System.out.println("该操作影响了:"+rows+"行");} catch (Exception e) {e.printStackTrace();}finally{if(rs !=null){try {rs.close();} catch (SQLException e) {e.printStackTrace();}finally{rs = null;}}if(stat !=null){try {stat.close();} catch (SQLException e) {e.printStackTrace();}finally{stat = null;}}if(conn !=null){try {conn.close();} catch (SQLException e) {e.printStackTrace();}finally{conn = null;}}}} }
改
//jdbc 改 public class Demo_01 {public static void main(String[] args) {Connection conn = null;Statement stat = null;ResultSet rs = null;try {//注册驱动Class.forName("com.mysql.jdbc.Driver");//获取连接conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/cszj","root","root");//获取传输器stat = conn.createStatement();//通过传输器将sql语句传输到mysql中int rows = stat.executeUpdate("update user set id = 5 where user='奥特曼'");//结果System.out.println("该操作影响了:"+rows+"行");} catch (Exception e) {e.printStackTrace();}finally{if(rs !=null){try {rs.close();} catch (SQLException e) {e.printStackTrace();}finally{rs = null;}}if(stat !=null){try {stat.close();} catch (SQLException e) {e.printStackTrace();}finally{stat = null;}}if(conn !=null){try {conn.close();} catch (SQLException e) {e.printStackTrace();}finally{conn = null;}}}} }
查
//jdbc 查 public class Demo_01 {public static void main(String[] args) {Connection conn = null;Statement stat = null;ResultSet rs = null;try {//注册驱动Class.forName("com.mysql.jdbc.Driver");//获取连接conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/cszj","root","root");//获取传输器stat = conn.createStatement();//通过传输器将sql语句传输到mysql中rs = stat.executeQuery("select * from user");//结果while(rs.next()){int id = rs.getInt("id");String user = rs.getString("user");String password = rs.getString("password");System.out.println(id+":"+user+":"+password);}} catch (Exception e) {e.printStackTrace();}finally{if(rs !=null){try {rs.close();} catch (SQLException e) {e.printStackTrace();}finally{rs = null;}}if(stat !=null){try {stat.close();} catch (SQLException e) {e.printStackTrace();}finally{stat = null;}}if(conn !=null){try {conn.close();} catch (SQLException e) {e.printStackTrace();}finally{conn = null;}}}} }
自定义JDBCUtils 工具类
创建配置文件 config.properties
driverClass=com.mysql.jdbc.Driver jdbcUrl=jdbc:mysql://localhost:3306/cszj user=root password=root
创建数据库工具类
/*** 数据库工具类* */ public class JDBCUtils {//只在类被加载时读取一次配置文件private static Properties prop = new Properties();static{try {String path = JDBCUtils.class.getClassLoader().getResource("config.properties").getPath();prop.load(new FileInputStream(path));} catch (Exception e) {e.printStackTrace();} }//获取连接public static Connection getConnection(){String driverClass = prop.getProperty("driverClass");String jdbcUrl = prop.getProperty("jdbcUrl");String user = prop.getProperty("user");String password = prop.getProperty("password");Connection conn = null;try {//注册驱动Class.forName(driverClass);//获取连接conn = DriverManager.getConnection(jdbcUrl,user,password);} catch (Exception e) {e.printStackTrace();}return conn;}//释放资源public static void close(Connection conn , Statement stat, ResultSet rs){if(rs !=null){try {rs.close();} catch (SQLException e) {e.printStackTrace();}finally{rs =null ;}}if(stat !=null){try {stat.close();} catch (SQLException e) {e.printStackTrace();}finally{stat =null ;}}if(conn !=null){try {conn.close();} catch (SQLException e) {e.printStackTrace();}finally{conn =null ;}} } }
修改数据路连接代码
//jdbc 查 public class Demo_01 {public static void main(String[] args) {Connection conn = null;Statement stat = null;ResultSet rs = null;try {//获取连接conn = JDBCUtils.getConnection();//获取传输器stat = conn.createStatement();//通过传输器将sql语句传输到mysql中rs = stat.executeQuery("select * from user");//结果while(rs.next()){int id = rs.getInt("id");String user = rs.getString("user");String password = rs.getString("password");System.out.println(id+":"+user+":"+password);}} catch (Exception e) {e.printStackTrace();}finally{JDBCUtils.close(conn, stat, rs);}} }
PreparedStatement
注入攻击演示
public static void main(String[] args) {Scanner scan = new Scanner(System.in);//提示用户登陆System.out.println("请登陆");//提示输入用户名System.out.println("请输入用户名:");String username = scan.nextLine();//提示输入密码System.out.println("请输入密码:");String password = scan.nextLine();login(username,password);}private static void login(String username, String password) {Connection conn = null;Statement stat = null;ResultSet rs = null;try {conn = JDBCUtils.getConnection();stat = conn.createStatement();String sql = "select * from user where username='"+username+"' and password='"+password+"'";//当输入“张三'#”后,sql变为://select * from user where username='张三'#' and password=''//当输入“张三' or '2=2”后,sql变为://select * from user where username='张三' or '2=2' and password=''rs = stat.executeQuery(sql);if(rs.next()){System.out.println("恭喜,登陆成功");}else{System.out.println("用户名或密码错误");}} catch (Exception e) {e.printStackTrace();throw new RuntimeException();}finally{JDBCUtils.close(conn, stat, rs);}}
- 由于后台的SQL是拼接而来的, 其中的参数是用户提交的, 如果用户在提交参数时, 参杂了一些SQL关键字或者特殊符号, 就有可能会导致SQL语句语意的改变, 从而造成一些意外的操作!
Preparedment
优点:
- 可以防止SQL注入攻击
- 通过PreparedStatement对象发送sql, 是先把sql语句的骨架发送给数据库编译并确定下来, 后面发送的只能是参数的值, 不能影响sql语句的骨架, 即使参数中包含sql关键字或特殊符号, 也只会当成普通的文本来处理!
- 通过 方法来设置参数 , 省去了拼接sql语句的麻烦
可以提高程序运行的效率
PreparedStatement对象发送的sql语句(骨架)到数据库编译后会被数据缓存下来, 如果下次执行的sql与缓存中的相匹配, 就不再编译而是直接使用缓存中的语句, 可以减少sql语句编译的次数, 提高程序执行的效率!
Statement对象发送的sql语句到数据库之后也会编译, 但是Statement对象是先拼接好再发送sql到数据库, 如果每次参数不同, 整条sql也就不同. 所以每次都需要编译!
- 可以防止SQL注入攻击
代码改造
//jdbc 查 public class Demo_01 {public static void main(String[] args) {Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try {//获取连接conn = JDBCUtils.getConnection();//获取传输器ps = conn.prepareStatement(" select * from user");//通过传输器将sql语句传输到mysql中rs = ps.executeQuery();//结果while(rs.next()){int id = rs.getInt("id");String user = rs.getString("user");String password = rs.getString("password");System.out.println(id+":"+user+":"+password);}} catch (Exception e) {e.printStackTrace();}finally{JDBCUtils.close(conn, ps, rs);}} }
二、批处理
- 批处理概述
- 假设现有一大堆的sql要到数据库执行, 如果一条一条发送, 有多少条就 需要发送多少次, 效率低下
- 可以通过批处理提高发送sql语句的效率: 可以将这一大堆的sql添加到 一个批中, 一次性将批发送给数据库, 数据库收到后打开批, 依次执行其中 sql语句, 这样可以减少sql语句发送的次数, 从而提高程序执行的效率!
Statement方式实现批处理
- 优点: 可以再一次批处理中添加结构不同的语句
- 缺点:
- 不能防止sql注入
- 没有预编译机制 , 效率贼低
- 当发送结构相同的sql语句时 , sql语句的骨架每次都需要编译 。
案例:
//批处理 public class Demo_02 {public static void main(String[] args) {Connection conn = null;Statement stat = null;ResultSet rs = null;try{//获取连接conn = JDBCUtils.getConnection();//获取传输器stat = conn.createStatement();stat.addBatch("use cszj;");stat.addBatch("create if not exists table tb_batch(id int primary key auto_increment, name varchar(20))");stat.addBatch("insert into tb_batch values(null,'a')");stat.addBatch("insert into tb_batch values(null,'b')");stat.addBatch("insert into tb_batch values(null,'c')");stat.addBatch("insert into tb_batch values(null,'d')");stat.executeBatch();System.out.println("执行完成");}catch(Exception e){e.printStackTrace();}finally{JDBCUtils.close(conn, stat, rs);}} }
PreparedStatement方式实现批处理
- 优点:
- 可以防止sql注入攻击
- 采用预编译机制 , 可以提高程序执行效率
- 当发送多条结构相同的sql时 , sql骨架只发送编译一次
- 缺点:
- 不能在一次批处理中添加不同结构的语句
案例:
//批处理 public class Demo_02 {public static void main(String[] args) {Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try{//获取连接conn = JDBCUtils.getConnection();//获取传输器ps = conn.prepareStatement("insert into tb_batch values(null ,? )");for( int i = 0;i<10;i++){ps.setString(1, "a"+i);ps.addBatch();}ps.executeBatch();System.out.println("执行完成");}catch(Exception e){e.printStackTrace();}finally{JDBCUtils.close(conn, ps, rs);}} }
- 优点:
三、数据库连接池
- 概述
- 用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出、宕机。
- 频繁的开关连接相当的耗费资源,所以我们可以设置一个连接池,在程序启动时就初始化一批连接,在程序中共享,需要连接时从池中获取,用完再还回池中,通过池共享连接,减少开关连接的次数,提高程序的效率。
自定义一个简易的数据库连接池
import java.io.PrintWriter; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.LinkedList; import java.util.List; import java.util.logging.Logger; import javax.sql.DataSource;public class MyPool implements DataSource{private static List<Connection> list = new LinkedList<Connection>();static{try {Class.forName("com.mysql.jdbc.Driver");for (int i = 0; i < 5; i++) {Connection conn = DriverManager.getConnection("jdbc:mysql:///mydb5","root","root");list.add(conn);}} catch (Exception e) {e.printStackTrace();throw new RuntimeException();}}@Overridepublic Connection getConnection() throws SQLException {if(list.isEmpty()){for (int i = 0; i < 3; i++) {Connection conn = DriverManager.getConnection("jdbc:mysql:///mydb1");list.add(conn);}}Connection conn = list.remove(0);System.out.println("成功从数据库中获取一个连接,连接池中还剩"+list.size()+"个连接..");return conn;}public void returnConn(Connection conn){try {if(conn != null && !conn.isClosed()){list.add(conn);System.out.println("成功向数据库还回一个连接,连接池中还剩"+list.size()+"个连接..");}} catch (SQLException e) {e.printStackTrace();throw new RuntimeException();}}@Overridepublic PrintWriter getLogWriter() throws SQLException {// TODO Auto-generated method stubreturn null;}@Overridepublic void setLogWriter(PrintWriter out) throws SQLException {// TODO Auto-generated method stub}@Overridepublic void setLoginTimeout(int seconds) throws SQLException {// TODO Auto-generated method stub}@Overridepublic int getLoginTimeout() throws SQLException {// TODO Auto-generated method stubreturn 0;}@Overridepublic Logger getParentLogger() throws SQLFeatureNotSupportedException {// TODO Auto-generated method stubreturn null;}@Overridepublic <T> T unwrap(Class<T> iface) throws SQLException {// TODO Auto-generated method stubreturn null;}@Overridepublic boolean isWrapperFor(Class<?> iface) throws SQLException {// TODO Auto-generated method stubreturn false;}@Overridepublic Connection getConnection(String username, String password)throws SQLException {// TODO Auto-generated method stubreturn null;} }测试自定义连接池import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement;public class TestMyPool {public static void main(String[] args) {MyPool pool = new MyPool();Connection conn= null;Statement stat = null;ResultSet rs = null;try {conn = pool.getConnection();stat = conn.createStatement();rs = stat.executeQuery("select * from account where id=1");if(rs.next()){System.out.println(rs.getInt("id")+":"+rs.getString("name")+":"+rs.getDouble("money"));}System.out.println("执行完毕");} catch (Exception e) {e.printStackTrace();throw new RuntimeException();}finally{if(rs!=null){try {rs.close();} catch (SQLException e) {e.printStackTrace();}finally{rs = null;}}if(stat!=null){try {stat.close();} catch (SQLException e) {e.printStackTrace();}finally{stat = null;}}pool.returnConn(conn);}} }
- 如上代码写的连接池,还需要在使用完连接后记得不能关闭连接,而是要调用returnConn方法将连接还回池中。
- 我们想能不能想办法改造conn的close方法,使close方法不会真的关闭连接而是将连接还回池中。
改造close方法
- 继承
- 写一个类继承要改造的类,对于不想改造的方法不覆盖,对于想要改造的方法复写该方法,将代码改造为自己需要的逻辑代码。
- 这种方式只能在还没有对象的情况下使用,现在Connection对象已经存在了,再用继承复写的方式是不行的,所以我们不采用。
- 装饰
- 实现装饰设计模式:
- 写一个装饰类, 要求装饰类和被装饰者所属的类实现同一个接口或者继承同一个父类
- 装饰类必须提供构造方法接收被装饰者, 并将被装饰者保存在类的内部
- 对于想要改造的方法直接进行改造, 对于不想改造的方法, 直接调用原有对象(被装设者)上的方法
- 实现装饰设计模式:
案例:
装饰者类 public class ConnectionDecorate implements Connection{private Connection conn = null;private MyPool pool = null;public ConnectionDecorate(Connection conn,MyPool pool){this.conn = conn;this.pool = pool;}@Overridepublic void close() throws SQLException {pool.returnConn(conn);}修改MyPool类:在获取连接方法中,return前加入如下代码: //先进行包装Connection connDecorate = new ConnectionDecorate(conn,this);return connDecorate;测试类最后只需关闭连接即可
- 继承
开源数据库连接池c3p0
- 概述
- 我们手写的连接池是比较简陋的,是为了讲解连接池的原理。其实在真实开发中可以使用开源的数据库连接池。其中C3P0是比较常用的一种。
c3p0示例
- 导入c3p0包
创建测试类
public static void main(String[] args) {Connection conn = null;Statement stat = null;ResultSet rs = null;try {//创建连接池ComboPooledDataSource cpds = new ComboPooledDataSource();//设置连接数据库的基本信息cpds.setDriverClass("com.mysql.jdbc.Driver");cpds.setJdbcUrl("jdbc:mysql:///mydb5");cpds.setUser("root");cpds.setPassword("root");//从连接池中获取连接conn = cpds.getConnection();stat = conn.createStatement();rs = stat.executeQuery("select * from account where id=1");if(rs.next()){System.out.println(rs.getInt("id")+" : "+rs.getString("name")+" : "+rs.getDouble("money"));}} catch (Exception e) {e.printStackTrace();throw new RuntimeException();}finally{JDBCUtils.close(conn, stat, rs);} }
上面的方法是将数据写死在代码中,不利于代码的维护 , 需要对代码进行改造
C3p0会默认读取一个配置文件,为c3p0-config.xml,(注意,名字不能改变,否则c3p0将无法读取)我们在src或者类似的源码目录下,创建一个c3p0-config.xml文件, 配置内容如下:
<?xml version="1.0" encoding="UTF-8"?> <c3p0-config><default-config><property name="driverClass">com.mysql.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql:///mydb5</property><property name="user">root</property><property name="password">root</property></default-config> </c3p0-config>
另一种方式:在src或者类似的源代码目录下, 创建一个c3p0.properties文件 , 配置文件内容如下:
c3p0.driverClass=com.mysql.jdbc.Driver c3p0.jdbcUrl=jdbc:mysql:///mydb5 c3p0.user=root c3p0.password=root
- 概述
大数据WEB阶段(七)JDBC、数据库批处理、数据库连接池相关推荐
- 大数据WEB阶段 TransientDateAccessResourceException
大数据WEB阶段 TransientDateAccessResourceException 一 . 分析 如果数据库保存的字段有时间 , 但是没有给该字段赋值时 ,则该字段默认是0000-00-00 ...
- 大数据WEB阶段Mybatis(一)
Mybatis(一) 零.目录 Mybatis介绍 Mybatis入门案例 增删改查练习 映射文件中取值问题 Mybatis中单值传递和多值传递问题 sql语句的复用 别名标签 动态更新 动态查询 动 ...
- 大数据WEB阶段(十八)数据库事务
数据库事务 一.概述 事务的概念 事务是指逻辑上的一组操作 , 组成这组操作的各个单元 , 要么全部成功 , 要么全部失败 . 如:银行转账.. 转账核心操作其实就是两条sql ,两条都执行成功才算成 ...
- 大数据WEB阶段总结
一.概述 HTTP协议 web容器 - Tomcat 静态web资源 - 本质上是文件 html css js 图片 音频 视频 flash- 动态web资源 - 本质上是程序 Servelt JSP ...
- 大数据WEB阶段 Maven与SSM框架整合
Maven整合SSM框架 零. 目录 Maven整合SSM 常见的问题 以及一些优化 一. Maven整合SSM 创建webapp工程 修改jdk和编译器 配置pom.xml文件 并在pom.xml文 ...
- 大数据WEB阶段(九)Servlet+Request
Servlet与Request 一.概述 Servlet 是sun公司提供的一门用于开发动态web资源的技术 按照这套规范写出来的servlet可以放置在web应用中在servlet容器中运行 . 开 ...
- 大数据WEB阶段 (六)MySql详解(一)
MySql(二) 一.概述 什么是数据库 数据库(Database)是按照数据结构来组织.存储和管理数据的仓库,简而言之就是存储数据的仓库. 数据库的分类 层次式数据库.网络式数据库.关系型数据库 数 ...
- java银行管理系统(MySql+JDBC+数据库(Druid数据库连接池)+GUI)重要代码有解析注释
java银行管理系统 小白又来水博客了 文章目录 java银行管理系统 一.项目需求与分析: 二.知识及有关技术的概述: 三.银行管理系统需求的具体实现: 四.部分功能预览: 五.Last: 一.项目 ...
- 大数据WEB阶段Mybatis(二)
Mybatis(二) 零.目录 Mybatis接口形式 Mybatis整合Spring Mybatis的缓存机制 手动封装结果集 一对一表操作 一对多表操作 多对多表操作 SpringMVC . Sp ...
最新文章
- NoSQL数据库四大分类
- 第二十课.卡尔曼滤波器
- golang中的runtime
- 大白鱼备考云笔记冲刺周期第一天
- java 三元 代替 if_Java 中三元和 if else 哪个的效率比较高,有底层解释吗,谢谢了!...
- kali linux 桌面消失_kalilinux系统设置不见了的解决方案
- linux进程cpu时间片,能讲一下在Linux系统中时间片是怎么分配的还有优先级的具体算法是...
- python123选择题及答案_py利用selenium库 爬取 python123官网的练习题及答案
- mfc编写鼠标键盘_黑客为什么都不用鼠标?进来你就懂了!
- apache mod_autoindex 详解
- 洛谷 P4568 [JLOI2011]飞行路线
- 实例3、研究 ICMP 数据包
- Matlab绘制单缝、光栅、圆孔、矩孔衍射图样
- 如何自学c语言更有效率,新手自学C语言提高效率的方法(混精)
- JavaScript 索引、关联、对象数组增删改查循环
- java证书验证失败_使用certbot证书验证失败
- python pygame 简单小游戏
- papers-06-07
- linux 使用pip安装出现错误
- Imagick的图像水印
热门文章
- Java字节码(.class文件)格式详解(一)
- 算法-动态规划(01背包)
- 关于织梦系统不支持php中GD库的问题
- 解决datagrid单元格不能设置100%问题
- 每日程序C语言34-利用指针将输入的三个数排序
- Java黑皮书课后题第1章:1.1(显示三条消息)编写程序,显示Welcome to Java、Welcome to Computer Science和Programming is fun
- VS2008 Tips #008 如何创建ASP.NET Web 用户控件并包含在Web 页面中
- java 23种设计模式 深入理解
- js 原型prototype继承模式
- 文本输入框内实时检测输入的字数