JDBC(Java Datdoase Connectivity)是一个独立于特定数据库管理系统,通用的SQL数据库存取和操作的公共接口(一组API ),定义了用来访问数据库的标准Java类库,( java.sql,javax.sql )使用这些类库可以以—种标准的方法、方便地访问数据库资源。JDBC为访问不同的数据库提供了一种统一的途径,为开发者屏蔽了一些细节问题。
JDBC的目标是使Java程序员使用JDBC可以连接任何提供了JDBC驱动程序的数据库系统,这样就使得程序员无需对特定的数据库系统的特点有过多的了解,从而大大简化和加快了开发过程。
导入mysql的驱动jar包
- 去mysql官网下载
- 在idea里面项目下建立一个lib文件夹,把解压后的jar文件放进去

- idea里面点击File——Project Structure——Modules——Dependencies——点击+号——JARs
加载驱动
mysql8以下版本:com.mysql.jdbc.Driver mysql8版本:com.mysql.cj.jdbc.Driver
//加载驱动Driver driver = new com.mysql.cj.jdbc.Driver();DriverManager.registerDriver(driver);//或者这么写,反射,都一样//Class.forName("com.mysql.cj.jdbc.Driver");
连接数据库
加载完驱动后既可以连接数据库了
DriverManager.getConnection()不知道哪个版本变强了,不需要注册驱动都能连接。高版本jdk下面代码一句话连接数据库,不需要注册驱动
mysql8以下版本:jdbc:mysql://localhost:3306/数据库名 mysql8版本:jdbc:mysql://localhost:3306/数据库名?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
Connection conn =null;//url数据库连接workersm是数据库,root是用户,123456是密码String url="jdbc:mysql://localhost:3306/workersm?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC";conn = DriverManager.getConnection(url,"root","123456");
用配置文件的方式连接
新建一个文件jdbc.properties放在包同级目录下,在里面写上配置信息,=别打空格
user=rootpassword=123456url=jdbc:mysql://localhost:3306/workersm?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTCdriverClass=com.mysql.cj.jdbc.Driver
在数据库连接类中写到
public static void connDB() throws IOException, ClassNotFoundException, SQLException {InputStream ips =DB.class.getClassLoader().getResourceAsStream("jdbc.properties");Properties p = new Properties();p.load(ips);String user = p.getProperty("user");String password = p.getProperty("password");String url = p.getProperty("url");String driverClass = p.getProperty("driverClass");Class.forName(driverClass);Connection conn = DriverManager.getConnection(url,user,password);System.out.println(conn);}
这样写的好处是,如果要换数据库,只需要改配置文件里面的东西,不用修改java代码
执行SQL语句
增删改
//使用PreparedStatement执行数据表的正删改查操作//增删改public static void Execute1() throws SQLException, IOException, ClassNotFoundException {//1.执行上面的方法,连接数据库connDB();//2.sql语句,???是通配符String sql = "insert into worktypes values(?,?,?,?)";//3.预编译sql语句,conn是数据库连接对象PreparedStatement p = conn.prepareStatement(sql);//4.填充占位符,是什么类型的数据就set什么类型,第一个参数为占位符的索引,从1开始,第二个参数为值p.setInt(1,Types.NULL);p.setString(2,"牛逼");p.setDouble(3,333.3);p.setDouble(4,44.4);//5.执行sql//boolean b1 = p.execute();//执行任何sql语句,如果返回的是数据集,就是true,否则falseint b2 = p.executeUpdate();//执行增删改,返回执行行数,或者没有if(b2>0)System.out.println("执行增删改成功"+b2);elseSystem.out.println("失败");//6.资源关闭p.close();conn.close();}
批量操作
这种添加效率低得很,以下数据用了73秒
long start = System.currentTimeMillis();for(int i=0;i<1000;i++){p.executeUpdate();//执行增删改,返回执行行数,或者没有}long end =System.currentTimeMillis();System.out.println("一共用时:"+(end-start)/1000+"秒");
Batch累计sql的方式
需要在连接数据库的url添加上参数
rewriteBatchedStatements=true
url=jdbc:mysql://localhost:3306/workersm?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC&rewriteBatchedStatements=true
每500条sql执行一次,10w条用时31秒,改为每5000条执行一次,用时4秒,速度和这个有直接关系
long start = System.currentTimeMillis();for(int i=0;i<100000;i++){p.addBatch();//累计sqlif(i%500==0){//累计500条sql执行1次p.executeBatch();//执行累计的sqlp.clearBatch();//清空}if(i==99999){p.executeBatch();//执行累计的sqlp.clearBatch();//清空}}long end =System.currentTimeMillis();System.out.println("一共用时:"+(end-start)/1000+"秒");
Batch统一提交数据,只用了1秒左右
long start = System.currentTimeMillis();conn.setAutoCommit(false);//设置不允许自动提交数据for(int i=0;i<100000;i++){p.addBatch();//累计sqlif(i%5000==0){//累计5000条sql执行1次p.executeBatch();//执行累计的sqlp.clearBatch();//清空}if(i==99999){p.executeBatch();//执行累计的sqlp.clearBatch();//清空}}conn.commit();//统一提交数据long end =System.currentTimeMillis();System.out.println("一共用时:"+(end-start)/1000+"秒");
查
写一个对象类
public class Worktypes {private int id;private String workname;private double wtdaymoney;private double wthourmoney;public void setId(int id) {this.id = id;}public void setWorkname(String workname) {this.workname = workname;}public void setWtdaymoney(double wtdaymoney) {this.wtdaymoney = wtdaymoney;}public void setWthourmoney(double wthourmoney) {this.wthourmoney = wthourmoney;}public int getId() {return id;}public String getWorkname() {return workname;}public double getWtdaymoney() {return wtdaymoney;}public double getWthourmoney() {return wthourmoney;}public Worktypes(int id, String workname, double wtdaymoney, double wthourmoney) {this.id = id;this.workname = workname;this.wtdaymoney = wtdaymoney;this.wthourmoney = wthourmoney;}}
查询代码
//查询public static void Execute2() throws SQLException, IOException, ClassNotFoundException {//1.执行上面的方法,连接数据库connDB();//2.sql语句String sql = "select *from worktypes";//3.预编译sqlPreparedStatement ps = conn.prepareStatement(sql);//4.设置参数,没有不写//5.执行查询返回结果集ResultSet rs = ps.executeQuery();//6.处理结果集//这里只实例化了一个对象,用的是ifif(rs.next()){//判断集合的下一条是否有数据,如果有,就返回true//获取当前这条数据的各个字段//1.1通过索引获取,索引值从1开始int id = rs.getInt(1);String workname =rs.getString(2);//1.2通过字段名获取double wtdaymoney=rs.getDouble("wtdaymoney");double wthourmoney=rs.getDouble("wthourmoney");//实例化对象Worktypes wt = new Worktypes(id,workname,wtdaymoney,wthourmoney);System.out.println("这是"+wt);}//7.关闭资源conn.close();ps.close();rs.close();}
用ArrayList获取全部值,第6步
ArrayList<Worktypes> wts = new ArrayList();while (rs.next()){int id = rs.getInt(1);String workname =rs.getString(2);double wtdaymoney=rs.getDouble("wtdaymoney");double wthourmoney=rs.getDouble("wthourmoney");Worktypes wt = new Worktypes(id,workname,wtdaymoney,wthourmoney);wts.add(wt);}//获取里面第3条数据的workname字段值System.out.println(wts.get(2).getWorkname());
通过反射赋值对象
//5.执行查询返回结果集ResultSet rs = ps.executeQuery();//获取结果集的元数据,里面包含了这个数据集的一些信息ResultSetMetaData rsmd = rs.getMetaData();int c = rsmd.getColumnCount();//获取结果集的列数if(rs.first()){Worktypes wts = new Worktypes();//处理结果集中每一行数据中的每一列for(int i =0;i<c;i++){//获取列值Object cvalue = rs.getObject(i+1);//获取列的列名。获取查询出来的数据集的标签名用 rsmd.getColumnLabel()String cname = rsmd.getColumnName(i+1);//通过反射给wts对象的cname列赋值cvalueField field = Worktypes.class.getDeclaredField(cname);field.setAccessible(true);field.set(wts,cvalue);}}
事务
数据一旦提交,就不能回滚了
DDL操作一旦执行就制动提交了 DML默认情况下执行,自动提交,可以通过set autocommit = false方式取消DML自动提交
代码
执行sql语句的方法
//执行一条增删改数据public static void Execute1UpdataSQL(Connection conn,String sql,Object ...args) throws SQLException {PreparedStatement p = conn.prepareStatement(sql);//预编译sql//填充占位符for(int i=0;i< args.length;i++){p.setObject(i+1,args[i]);}p.executeUpdate();p.close();//事务里面单条sql语句不能关闭连接,可以关闭p}
执行多条sql语句形成事务
public static void main(String[] args) throws SQLException {Connection connection = null;try {connection = MysqlDB.getConnection();//获取一个连接connection.setAutoCommit(false);//设置不自动提交//执行第一个sql语句,不提交String sql1 = "delete from worktypes where id>5";MysqlDB.Execute1UpdataSQL(connection,sql1);//执行第二个sql语句,不提交String sql2 = "insert into worktypes values(?,?,?,?)";MysqlDB.Execute1UpdataSQL(connection,sql2, Types.NULL,"事务测试",888.88,99.99);connection.commit();//最后统一提交前面的sql语句} catch (Exception throwables) {throwables.printStackTrace();try {connection.rollback();//如果发生错误,就回滚} catch (SQLException e) {e.printStackTrace();}}finally {connection.close();//如果不想关闭连接,连接对象还要接着用,记得把自动提交打开connection.setAutoCommit(true)}}
属性
原子性
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
一致性
隔离性
事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
持久性
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响。
