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

导入mysql的驱动jar包

  1. 去mysql官网下载
  2. 在idea里面项目下建立一个lib文件夹,把解压后的jar文件放进去

image.png

  1. idea里面点击File——Project Structure——Modules——Dependencies——点击+号——JARs

选择lib文件夹下的jar包,先应用在确定

加载驱动

mysql8以下版本:com.mysql.jdbc.Driver mysql8版本:com.mysql.cj.jdbc.Driver

  1. //加载驱动
  2. Driver driver = new com.mysql.cj.jdbc.Driver();
  3. DriverManager.registerDriver(driver);
  4. //或者这么写,反射,都一样
  5. //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

  1. Connection conn =null;
  2. //url数据库连接workersm是数据库,root是用户,123456是密码
  3. String url="jdbc:mysql://localhost:3306/workersm?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC";
  4. conn = DriverManager.getConnection(url,"root","123456");

用配置文件的方式连接

新建一个文件jdbc.properties放在包同级目录下,在里面写上配置信息,=别打空格

  1. user=root
  2. password=123456
  3. url=jdbc:mysql://localhost:3306/workersm?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
  4. driverClass=com.mysql.cj.jdbc.Driver

在数据库连接类中写到

  1. public static void connDB() throws IOException, ClassNotFoundException, SQLException {
  2. InputStream ips =DB.class.getClassLoader().getResourceAsStream("jdbc.properties");
  3. Properties p = new Properties();
  4. p.load(ips);
  5. String user = p.getProperty("user");
  6. String password = p.getProperty("password");
  7. String url = p.getProperty("url");
  8. String driverClass = p.getProperty("driverClass");
  9. Class.forName(driverClass);
  10. Connection conn = DriverManager.getConnection(url,user,password);
  11. System.out.println(conn);
  12. }

这样写的好处是,如果要换数据库,只需要改配置文件里面的东西,不用修改java代码

执行SQL语句

增删改

  1. //使用PreparedStatement执行数据表的正删改查操作
  2. //增删改
  3. public static void Execute1() throws SQLException, IOException, ClassNotFoundException {
  4. //1.执行上面的方法,连接数据库
  5. connDB();
  6. //2.sql语句,???是通配符
  7. String sql = "insert into worktypes values(?,?,?,?)";
  8. //3.预编译sql语句,conn是数据库连接对象
  9. PreparedStatement p = conn.prepareStatement(sql);
  10. //4.填充占位符,是什么类型的数据就set什么类型,第一个参数为占位符的索引,从1开始,第二个参数为值
  11. p.setInt(1,Types.NULL);
  12. p.setString(2,"牛逼");
  13. p.setDouble(3,333.3);
  14. p.setDouble(4,44.4);
  15. //5.执行sql
  16. //boolean b1 = p.execute();//执行任何sql语句,如果返回的是数据集,就是true,否则false
  17. int b2 = p.executeUpdate();//执行增删改,返回执行行数,或者没有
  18. if(b2>0)
  19. System.out.println("执行增删改成功"+b2);
  20. else
  21. System.out.println("失败");
  22. //6.资源关闭
  23. p.close();
  24. conn.close();
  25. }

批量操作

  1. 这种添加效率低得很,以下数据用了73秒

    1. long start = System.currentTimeMillis();
    2. for(int i=0;i<1000;i++){
    3. p.executeUpdate();//执行增删改,返回执行行数,或者没有
    4. }
    5. long end =System.currentTimeMillis();
    6. System.out.println("一共用时:"+(end-start)/1000+"秒");
  2. Batch累计sql的方式

    需要在连接数据库的url添加上参数rewriteBatchedStatements=true

  1. url=jdbc:mysql://localhost:3306/workersm?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC&rewriteBatchedStatements=true

每500条sql执行一次,10w条用时31秒,改为每5000条执行一次,用时4秒,速度和这个有直接关系

  1. long start = System.currentTimeMillis();
  2. for(int i=0;i<100000;i++){
  3. p.addBatch();//累计sql
  4. if(i%500==0){//累计500条sql执行1次
  5. p.executeBatch();//执行累计的sql
  6. p.clearBatch();//清空
  7. }
  8. if(i==99999){
  9. p.executeBatch();//执行累计的sql
  10. p.clearBatch();//清空
  11. }
  12. }
  13. long end =System.currentTimeMillis();
  14. System.out.println("一共用时:"+(end-start)/1000+"秒");
  1. Batch统一提交数据,只用了1秒左右

    1. long start = System.currentTimeMillis();
    2. conn.setAutoCommit(false);//设置不允许自动提交数据
    3. for(int i=0;i<100000;i++){
    4. p.addBatch();//累计sql
    5. if(i%5000==0){//累计5000条sql执行1次
    6. p.executeBatch();//执行累计的sql
    7. p.clearBatch();//清空
    8. }
    9. if(i==99999){
    10. p.executeBatch();//执行累计的sql
    11. p.clearBatch();//清空
    12. }
    13. }
    14. conn.commit();//统一提交数据
    15. long end =System.currentTimeMillis();
    16. System.out.println("一共用时:"+(end-start)/1000+"秒");

    写一个对象类

    1. public class Worktypes {
    2. private int id;
    3. private String workname;
    4. private double wtdaymoney;
    5. private double wthourmoney;
    6. public void setId(int id) {
    7. this.id = id;
    8. }
    9. public void setWorkname(String workname) {
    10. this.workname = workname;
    11. }
    12. public void setWtdaymoney(double wtdaymoney) {
    13. this.wtdaymoney = wtdaymoney;
    14. }
    15. public void setWthourmoney(double wthourmoney) {
    16. this.wthourmoney = wthourmoney;
    17. }
    18. public int getId() {
    19. return id;
    20. }
    21. public String getWorkname() {
    22. return workname;
    23. }
    24. public double getWtdaymoney() {
    25. return wtdaymoney;
    26. }
    27. public double getWthourmoney() {
    28. return wthourmoney;
    29. }
    30. public Worktypes(int id, String workname, double wtdaymoney, double wthourmoney) {
    31. this.id = id;
    32. this.workname = workname;
    33. this.wtdaymoney = wtdaymoney;
    34. this.wthourmoney = wthourmoney;
    35. }
    36. }

    查询代码

    1. //查询
    2. public static void Execute2() throws SQLException, IOException, ClassNotFoundException {
    3. //1.执行上面的方法,连接数据库
    4. connDB();
    5. //2.sql语句
    6. String sql = "select *from worktypes";
    7. //3.预编译sql
    8. PreparedStatement ps = conn.prepareStatement(sql);
    9. //4.设置参数,没有不写
    10. //5.执行查询返回结果集
    11. ResultSet rs = ps.executeQuery();
    12. //6.处理结果集
    13. //这里只实例化了一个对象,用的是if
    14. if(rs.next()){//判断集合的下一条是否有数据,如果有,就返回true
    15. //获取当前这条数据的各个字段
    16. //1.1通过索引获取,索引值从1开始
    17. int id = rs.getInt(1);
    18. String workname =rs.getString(2);
    19. //1.2通过字段名获取
    20. double wtdaymoney=rs.getDouble("wtdaymoney");
    21. double wthourmoney=rs.getDouble("wthourmoney");
    22. //实例化对象
    23. Worktypes wt = new Worktypes(id,workname,wtdaymoney,wthourmoney);
    24. System.out.println("这是"+wt);
    25. }
    26. //7.关闭资源
    27. conn.close();
    28. ps.close();
    29. rs.close();
    30. }

    用ArrayList获取全部值,第6步

    1. ArrayList<Worktypes> wts = new ArrayList();
    2. while (rs.next()){
    3. int id = rs.getInt(1);
    4. String workname =rs.getString(2);
    5. double wtdaymoney=rs.getDouble("wtdaymoney");
    6. double wthourmoney=rs.getDouble("wthourmoney");
    7. Worktypes wt = new Worktypes(id,workname,wtdaymoney,wthourmoney);
    8. wts.add(wt);
    9. }
    10. //获取里面第3条数据的workname字段值
    11. System.out.println(wts.get(2).getWorkname());

    通过反射赋值对象

    1. //5.执行查询返回结果集
    2. ResultSet rs = ps.executeQuery();
    3. //获取结果集的元数据,里面包含了这个数据集的一些信息
    4. ResultSetMetaData rsmd = rs.getMetaData();
    5. int c = rsmd.getColumnCount();//获取结果集的列数
    6. if(rs.first()){
    7. Worktypes wts = new Worktypes();
    8. //处理结果集中每一行数据中的每一列
    9. for(int i =0;i<c;i++){
    10. //获取列值
    11. Object cvalue = rs.getObject(i+1);
    12. //获取列的列名。获取查询出来的数据集的标签名用 rsmd.getColumnLabel()
    13. String cname = rsmd.getColumnName(i+1);
    14. //通过反射给wts对象的cname列赋值cvalue
    15. Field field = Worktypes.class.getDeclaredField(cname);
    16. field.setAccessible(true);
    17. field.set(wts,cvalue);
    18. }
    19. }

    事务

    数据一旦提交,就不能回滚了

    DDL操作一旦执行就制动提交了 DML默认情况下执行,自动提交,可以通过set autocommit = false方式取消DML自动提交

代码

执行sql语句的方法

  1. //执行一条增删改数据
  2. public static void Execute1UpdataSQL(Connection conn,String sql,Object ...args) throws SQLException {
  3. PreparedStatement p = conn.prepareStatement(sql);//预编译sql
  4. //填充占位符
  5. for(int i=0;i< args.length;i++){
  6. p.setObject(i+1,args[i]);
  7. }
  8. p.executeUpdate();
  9. p.close();//事务里面单条sql语句不能关闭连接,可以关闭p
  10. }

执行多条sql语句形成事务

  1. public static void main(String[] args) throws SQLException {
  2. Connection connection = null;
  3. try {
  4. connection = MysqlDB.getConnection();//获取一个连接
  5. connection.setAutoCommit(false);//设置不自动提交
  6. //执行第一个sql语句,不提交
  7. String sql1 = "delete from worktypes where id>5";
  8. MysqlDB.Execute1UpdataSQL(connection,sql1);
  9. //执行第二个sql语句,不提交
  10. String sql2 = "insert into worktypes values(?,?,?,?)";
  11. MysqlDB.Execute1UpdataSQL(connection,sql2, Types.NULL,"事务测试",888.88,99.99);
  12. connection.commit();//最后统一提交前面的sql语句
  13. } catch (Exception throwables) {
  14. throwables.printStackTrace();
  15. try {
  16. connection.rollback();//如果发生错误,就回滚
  17. } catch (SQLException e) {
  18. e.printStackTrace();
  19. }
  20. }finally {
  21. connection.close();
  22. //如果不想关闭连接,连接对象还要接着用,记得把自动提交打开connection.setAutoCommit(true)
  23. }
  24. }

属性

原子性

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

一致性

事务必须使数据库从一个一致性状态变换到另外一个一致性状态。

隔离性

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

持久性

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