使用JDBC连接数据库及书写套路

1.JDBC简介

  • jdbc(Java DataBase Connectivity)

    在C语言的Odbc基础上发展而来,是最早的ORM(Object Relation Mapping对象映射关系)工具,可以使用面向对象的Java代码
    对关系型数据库进行操作。
    ORM工具随着不断的发展衍生出了很多框架那么大部分框架都是在JDBC基础上发展而来,JDBC是几乎所有框架的基础,也是效率最高的ORM工具
    JDBC是第一方技术,所有的接口等全部放置在java.sql包中

    全手动 JDBC
    半自动 myBatis
    全自动 Hibernate

    1)创建关系表
    2)创建实体类
    A:一般放置在com.etoak.po包中或者bean包中
    B:尽量使用包装类封装字段,字段名对应
    C:必须书写空参构造方法,酌情覆盖有参构造方法
    D:酌情覆盖toString()
    3)创建工厂类
    A:工厂类一般放置在com.etoak.factory包中,此类链接数据库
    B:加载驱动,只需要加载一次放置在静态初始化块中
    C:封装一个方法返回链接
    4)书写dao层
    A:dao层全部放置在com.etoak.dao包中
    B:接口用来设置需要被实现的方法
    C:实现类实现接口中的方法

创建数据表

DROP table if EXISTS  person;
CREATE  table person (
  id     INT PRIMARY KEY AUTO_INCREMENT,
  name   VARCHAR(10) NOT NULL,
  pass   VARCHAR(10) NOT NULL,
  age    INT,
  salary DOUBLE,
  birth  DATE
);
insert INTO person VALUES (null,'elena','12345',20,5000.00,'1990-06-03');
insert INTO person VALUES (null,'penny','123465',30,6000.00,'1993-06-13');
insert INTO person VALUES (null,'aleric','1234545',40,7000.00,'1992-06-05');
insert INTO person VALUES (null,'bonnie','1432345',20,3000.00,'1996-06-03');
insert INTO person VALUES (null,'matt','123345',24,15000.00,'1997-06-04');
insert INTO person VALUES (null,'damon','123445',23,25000.00,'1992-06-04');
insert INTO person VALUES (null,'用户名','1232245',29,5000.00,'1998-07-01');

1. JavaBean实体类

如果一个Java类仅仅封装了属性,没有其他方法,则称之为POJO类或实体类,好像也叫作JavaBean,通常放置在com.xxx.po 或者 com,xxx.bean 包中

这个类中封装的属性必须对用数据库中的字段,必须覆盖空参的构造方法,酌情覆盖全参构造方法,酌情覆盖toString()方法

public class Person{
    //使用包装类封装字段,必须对应表中的字段
	private Integer id;
	private String name;
	private String pass;
	private Integer age;
	private Double salary;
	private Date birth;
    
    /*
	*   必须覆盖空参的构造方法
	*   覆盖空参构造方法之后可以new空参的对象
	*   Person per = new Person();
	* */
	public Person() {
	}
    /*
	*   酌情覆盖全参构造方法,这样我们就可以直接new一个带有六个参数的对象
	*   Person per = new Person(XX,XX,XX,XX,XX,XX);
	* */
	public Person(Integer id, String name, String pass, Integer age, Double salary, Date birth) {
		this.id = id;
		this.name = name;
		this.pass = pass;
		this.age = age;
		this.salary = salary;
		this.birth = birth;
	}
    //各个属性的get和set方法
    //看需求是否覆盖 toString() 方法
}

2. 工厂类

  • 一般放置在**com.xxx.factory包中**

1.加载驱动

static{
    try{
        Class.forName("com.mysql.jdbc.Driver");
    }catch(Exception e){
        e.printStackTrace();
    }
}

2.获取链接

public static Connection getConn(){
        try{
            //2.加载链接
            /*
            * 完全版:
            *       jdbc:mysql://localhost:端口号/database
            *       jdbc:mysql://远程ip地址:端口号/database
            * 如果数据库在本地,则可以使用简化版:
            *       jbdc:mysql:///database
            * user:用户名
            * password:用户密码
            * */
            return DriverManager.getConnection("jdbc:mysql:///et1912","root","dream");
        }catch(Exception e){
            e.printStackTrace();
            return null;
        }
    }

3.释放资源

public static void close(ResultSet rs, Statement st,Connection con){
		try {
			if(rs!=null)
				rs.close();
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			try {
				if(st!=null)
					st.close();
			} catch (Exception ex) {
				ex.printStackTrace();
			} finally {
				try {
					if(con!=null)
						con.close();
				} catch (Exception ex) {
					ex.printStackTrace();
				}
			}
		}
	}

代码

package com.etoak.factory;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class Factory {
	/*
	*   A:加载驱动
	*       不同的数据库品牌厂商提供了不同的驱动,可以正确识别各种厂商的数据库品牌
	*       语法等,加载驱动之后,在Java端可以使用相同的Java代码操作不同品牌不同语法的数据库
			此处使用静态初始化块仅仅加载一次即可
	* */
	static{
		try {
			//使用反射类加载的方式加载驱动
			//不同品牌的驱动不同,需要导入数据库厂商提供的jar包
			Class.forName("com.mysql.jdbc.Driver");
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}


	/*
	*   B:获取连接
	*       连接数据库,通过驱动管理器提供连接地址,用户名和密码可以链接数据库
	* */
	public static Connection getCon(){
		try {
			/*
			*   注意这里三个参数分别是
			*       url:链接地址
			*       格式完全版
			*           jdbc:mysql://localhost:8080/数据库名
			*           jdbc:mysql://远程ip地址:8080/数据库名
			*       如果数据库就在本地,则可以使用简化版
			*           jdbc:mysql:///数据库名
			*       user:用户名
			*       password:密码
			* */
			return DriverManager.getConnection(
			"jdbc:mysql:///et1912","root","etoaketoak");
		} catch (Exception ex) {
			ex.printStackTrace();
			return null;
		}
	}

	/*
	*   C:释放资源
	*       释放资源时顺序如下:
	*           首先关闭结果集,关闭执行器,最后关闭连接
	* */
	public static void close(ResultSet rs, Statement st,Connection con){
		try {
			if(rs!=null)
				rs.close();
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			try {
				if(st!=null)
					st.close();
			} catch (Exception ex) {
				ex.printStackTrace();
			} finally {
				try {
					if(con!=null)
						con.close();
				} catch (Exception ex) {
					ex.printStackTrace();
				}
			}
		}
	}
}

3.dao持久化层

  • dao(Data Access Object) 数据访问对象
  • 通常放置在**com.xxx.dao包下**

1. 接口

/*
*   Dao:Data Access Object数据访问对象
*   这里的接口一般由项目经理或者一些规范的制定者来执行
*   如何实现不关心,仅仅提供了一个规范
*   DaoIf 是DaoInterface的简写
* */
public interface PersonDaoIf {

	//添加一个用户
	public boolean addPerson(Person per);

	//根据id删除一个用户
	public boolean delPersonById(Integer id);

	//拿取全部用户
	public List<Person> queryAll();

	//根据用户名查询
	public boolean queryName(String name);

	//根据用户名和密码查询
	public Person queryPerson(String name,String pass);

	//修改用户资料
	public boolean updatePerson(Person per);

}
public interface PersonDaoIf2 {
	//1添加用户
	public boolean addPerson(Person per);

	//2根据id删除
	public boolean delPersonById(Integer id);

	//3根据name删除
	public boolean delPersonByName(String name);

	//4拿取全部
	public List<Person> queryAll();

	//5姓名查重
	public boolean queryName(String name);

	//6登录查询
	public Person queryPerson(String name,String pass);

	//7拿取总记录数
	public Integer queryCount();

	//8分页查询
	public List<Person> queryPage(Integer index,Integer max);

	//9姓名模糊分页查询
	public List<Person> queryNameLikePage(String args,Integer index,Integer max);

	//10条件分页查询
	public List<Person> queryLikePage(Person per,Integer index,Integer max);

	//11批量删除
	public boolean multiDel(String[] args);

	//12修改
	public boolean updatePerson(Person per);
}

2.接口实现类[Statement]

  • 创建 PersonDaoIf 接口的实现类 PersonDaoImpl
  • 右键空白处 **(或者alt + insert)**选择 Implements Method,实现接口中的抽象方法
public class PersonDaoImpl implements PersonDaoIf{
    //设置连接
    Connection conn;
    //设置执行器
    Statement st;
    //结果集
    ResultSet rs;
    @Override
	public boolean addPerson(Person per) {
		try {
			//书写sql语句
			/*
			*   java.util.Date无法和字符串直接通过+拼接成sql语句
			*   可以有以下两种方式
			*   1)将java.util.Date转换为java.sql.Date,可以直接拼接
			*   2)将java.util.Date转换为字符串
			*
			*
			* */
			String sql =
			"insert into person values (null,'"+per.getName()+"','"+per.getPass()+"',"+per.getAge()+","
			+per.getSalary()+",'"+new SimpleDateFormat("yyyy-MM-dd").format(per.getBirth()) +"')";

			//获取连接
			con = Factory.getCon();

			//拿取执行器
			st = con.createStatement();

			//执行器根据sql语句调用方法
			return st.executeUpdate(sql)==1;

		} catch (Exception ex) {
			ex.printStackTrace();
			return false;
		} finally {
			//不管是否执行正常都要释放资源
			Factory.close(null,st,con);
		}
	}
}
存在的安全隐患
  • 当传入的是一个恒等的条件表达式的时候,语句相当于查找全表数据
  • 可以被SQL注入

3.接口实现类[PreparedStatement]

  • 创建类PersonDaoImpl2实现PersonDaoIf2接口
  • PreparedStatement是Statement的子类
  • 使用PreparedStatement执行器时,使用 ? 先进行站位,后填充
  • 填充日期类型时,需要用**new java.sql.Date(xxx.getDate().getTime())**
package com.etoak.dao;

import com.etoak.factory.Factory;
import com.etoak.po.Person;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

public class PersonDaoImpl2 implements PersonDaoIf2 {

	Connection con;
	Statement st;
	/*
	*   使用执行器PreparedStatement,它是Statement的子类
	* */
	PreparedStatement pst;
	ResultSet rs;

	@Override
	public boolean addPerson(Person per) {
		try {
			/*
			*   在使用Statement时,需要我们对sql语句进行拼接,但是在进行拼接时非常的不方便,
			*   并且安全性较低,容易出现sql注入安全隐患
			*   使用PreparedStatement则可以使用?作为占位符的形式来组装sql语句,不再需要我们
			*   进行复杂的sql拼接了
			*
			*   注意使用?占位,必须填充占位符,因为sql语句中不能再执行时存在?
			* */
			String sql = "insert into person values (null,?,?,?,?,?)";
			con = Factory.getCon();
			//获取执行器的同时,加载带有?占位符的sql语句
			pst = con.prepareStatement(sql);
			//由于存在占位符所以必须填充
			/*
			*   pst.set数据类型(index,要填充的值)
			*   index:表示从左往右?的顺序,注意从1开始
			* */
			pst.setString(1,per.getName());
			pst.setString(2,per.getPass());
			pst.setInt(3,per.getAge());
			pst.setDouble(4,per.getSalary());
			/*
			*   java.util.Date和java.sql.Date的区别
			*
			*   1)java.util.Date是sql.Date的父类
			*   2)util.Date一般可以设置年月日小时分钟秒
			*   而sql.Date只能精确到年月日
			*   3)util.Date不能和字符串直接拼接成sql语句
			*   而sql.Date可以
			*   4)通过getTime()进行转换
			* */
			pst.setDate(5,new java.sql.Date(per.getBirth().getTime()));
			return pst.executeUpdate()==1;
		} catch (Exception ex) {
			ex.printStackTrace();
			return false;
		} finally {
			//长按ctrl或者command键可以溯源
			Factory.close(null,pst,con);
		}
	}

	@Override
	public boolean delPersonById(Integer id) {
		try {
			String sql = "delete from person where id = ?";
			con = Factory.getCon();
			//获取执行器的同时加载sql语句
			pst = con.prepareStatement(sql);
			pst.setInt(1,id);
			return pst.executeUpdate()==1;
		} catch (Exception ex) {
			ex.printStackTrace();
			return false;
		} finally {
			Factory.close(null,pst,con);
		}
	}

	@Override
	public boolean delPersonByName(String name) {
		try {
			String sql = "delete from person where name = ?";
			con = Factory.getCon();
			pst = con.prepareStatement(sql);
			pst.setString(1,name);
			return pst.executeUpdate()>=1;
		} catch (Exception ex) {
			ex.printStackTrace();
			return false;
		} finally {
			Factory.close(null,pst,con);
		}
	}

	@Override
	public List<Person> queryAll() {
		try {
			String sql = "select * from person";
			con = Factory.getCon();
			pst = con.prepareStatement(sql);
			rs = pst.executeQuery();
			List<Person> list = new ArrayList<>();
			while(rs.next()){
				list.add(new Person(rs.getInt(1),
						rs.getString(2),rs.getString(3),rs.getInt(4)
				,rs.getDouble(5),rs.getDate(6)));
			}
			return list;
		} catch (Exception ex) {
			ex.printStackTrace();
			return null;
		} finally {
			Factory.close(rs,pst,con);
		}
	}

	@Override
	public boolean queryName(String name) {
		try {
			String sql = "select * from person where name = ?";
			con = Factory.getCon();
			pst = con.prepareStatement(sql);
			pst.setString(1,name);
			return pst.executeQuery().next();
		} catch (Exception ex) {
			ex.printStackTrace();
			return false;
		} finally {
			Factory.close(rs,pst,con);
		}
	}

	@Override
	public Person queryPerson(String name, String pass) {
		try {
			String sql = "select * from person where name = ? and pass = ?";
			con = Factory.getCon();
			pst = con.prepareStatement(sql);
			pst.setString(1,name);
			pst.setString(2,pass);
			rs = pst.executeQuery();
			if(rs.next()){
				return new Person(rs.getInt(1),
						rs.getString(2),rs.getString(3)
				,rs.getInt(4),rs.getDouble(5),rs.getDate(6));
			}
			return null;
		} catch (Exception ex) {
			ex.printStackTrace();
			return null;
		} finally {
			Factory.close(rs,pst,con);
		}
	}

	@Override
	public Integer queryCount() {
		try {
			String sql = "select count(*) from person";
			con = Factory.getCon();
			pst = con.prepareStatement(sql);
			rs = pst.executeQuery();
			/*
			*   这里的rs返回的是一个两行一列的表格
			*       ------------
			*       |          |
			*       |  count   |
			*       ------------
			*       |          |
			*       |  记录数   |
			*       ------------
			*
			*   指针指向表头,使其下移一行
			*/
			rs.next();
			return rs.getInt(1);
		} catch (Exception ex) {
			ex.printStackTrace();
			return null;
		} finally {
			Factory.close(rs,pst,con);
		}
	}

	@Override
	public List<Person> queryPage(Integer index, Integer max) {
		try {
			/*
			*   select 字段 from 表 limit x,y;
			*   x:表示起始索引值
			*   y:表示显示几条记录
			* */
			String sql = "select * from person limit ?,?";
			con = Factory.getCon();
			pst = con.prepareStatement(sql);
			pst.setInt(1,index);
			pst.setInt(2,max);
			rs = pst.executeQuery();
			List<Person> list = new ArrayList<>();
			while(rs.next()){
				list.add(new Person(rs.getInt(1),
						rs.getString(2),
						rs.getString(3),
						rs.getInt(4),
						rs.getDouble(5),
						rs.getDate(6)));
			}
			return list;
		} catch (Exception ex) {
			ex.printStackTrace();
			return null;
		} finally {
			Factory.close(rs,pst,con);
		}
	}

	//根据姓名模糊查询并且分页
	@Override
	public List<Person> queryNameLikePage(String args, Integer index, Integer max) {
		try {
			String sql = "select * from person where name like ? limit ?,?";
			con = Factory.getCon();
			pst = con.prepareStatement(sql);
			//对左模糊右模糊进行拼接
			pst.setString(1,"%"+args+"%");
			pst.setInt(2,index);
			pst.setInt(3,max);
			rs = pst.executeQuery();
			List<Person> list = new ArrayList<>();
			while(rs.next()){
				list.add(new Person(rs.getInt("id")
				,rs.getString("name")
				,rs.getString("pass")
				,rs.getInt("age")
				,rs.getDouble("salary")
				,rs.getDate("birth")));
			}
			return list;
		} catch (Exception ex) {
			ex.printStackTrace();
			return null;
		} finally {
			Factory.close(rs,pst,con);
		}
	}

	@Override
	public List<Person> queryLikePage(Person per, Integer index, Integer max) {
		return null;
	}

	/*
	*   此处传入的是字符串类型的数组,内部封装了所有的id
	*   根据这些id批量删除,注意不需要考虑id的真实性情况
	*
	* */
	@Override
	public boolean multiDel(String[] args) {
		try {
			String sql = "delete from person where id in (";
			String sum = "";
			for(int i = 0;i<args.length;i++){
				sum = args[i]+","+sum;
			}
			sum = sum.substring(0,sum.length()-1);
			sql += sum+")";

			con = Factory.getCon();
			st = con.createStatement();
			/*
			*   pst = con.preparedStatement(sql);
			*   pst.executeUpdate()>=1
			* */
			return st.executeUpdate(sql)>=1;
		} catch (Exception ex) {
			ex.printStackTrace();
			return false;
		} finally {
			Factory.close(null,pst,con);
		}
	}

	@Override
	public boolean updatePerson(Person per) {
		try {
			String sql =
			"update person set name = ?,pass = ?,age = ?,salary = ?,birth = ? where id = ?";
			con = Factory.getCon();
			pst = con.prepareStatement(sql);
			pst.setString(1,per.getName());
			pst.setString(2,per.getPass());
			pst.setInt(3,per.getAge());
			pst.setDouble(4,per.getSalary());
			pst.setDate(5,new java.sql.Date(per.getBirth().getTime()));
			pst.setInt(6,per.getId());
			return pst.executeUpdate()==1;
		} catch (Exception ex) {
			ex.printStackTrace();
			return false;
		} finally {
			Factory.close(null,pst,con);
		}
	}
}

1.书写套路注意事项

  1. Statement执行器
//在实现的方法中,第一步现获取连接
conn = Factory.getConn();
//第二步,获取执行器
st = conn.createStatement();
//第三步。书写Sql语句,这里可以先将SQL语句写完整之后在根据是否是字符类型的加双引号
String sql = "select * from person";
//如果没有返回结果集,则返回执行结果,
//此方法返回的是受影响的行数,返回值为int
return st.executeUpdate(sql) > 0;
//如果有返回结果集,则第四步,获得结果集
rs = st.executeQuery(sql);
//第五步,创建一个新的空集合,给定泛型确保只能存储该类型的对象
List<Person> list = new ArrayList<>();
//第六步 把结果集中的结果依次添加到空集合中
while(rs.next()){
    list.add(new Person(rs.getInt(1),...));
}
//第七步,关闭连接
Factory.closeConn(rs,st,conn);
  1. PreparedStatement执行器
//1获取连接
conn = Factory.getConn();
//2.书写sql语句,先使用占位符 ? 来填充
String sql = "select * from person where name like ? limit ?,?";
//3.获取执行器d的同时把sql语句传入
pst = conn.preparedStatement(sql);
//4.给占位符传入相应的值,第一个参数代表是sql语句中第几个问号,第二个参数代表传入的值
//4.1 模糊查询时拼接字符串
pst.setString(1,"%" + per.getName() + "%");
//4.2传入其他参数
pst.setInt(2,per.getAge());
//4.3 Date类型,因为util.Date不能拼接sql语句,所以要转化成sql.Date
pst.setDate(3,new java.sql.Date(per.getBirth().getTime()));
//5.执行
pst.executeQuery();

2. Date注意事项

  1. 执行sql语句拼接Date时
  • java.util.Date无法和字符串直接通过+拼接成sql语句

可以有以下两种方式

​ 1)将java.util.Date转换为java.sql.Date,可以直接拼接

​ 2)将java.util.Date转换为字符串

String sql = "insert into person values('"+ new SimpleDateFormat("yyyy-MM-dd").format(Date) +"')"
  1. 创建对象把String转换成Date类型时
Person per = new Person(new SimpleDateFormat("yyyy-MM-dd").parse("1999-01-01"));
  1. PreparedStatement传入Date
pst = conn.preparedStatement(sql);
pst.setDate(1,new java.sql.Date(per.getBirth().getTime()));

4. 测试

package com.etoak.test;

import com.etoak.factory.Factory;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

public class Test {
	public static void main(String[] args) {
		try {
			//调用工厂获取连接,从而链接数据库
			Connection con = Factory.getCon();
			/*
			*   如果出现Can not found class com.mysql.jdbc.Driver则是没导包
			*   或者驱动书写错误
			* */
			if(con==null){
				System.out.println("链接失败!!");
				return;
			}
			System.out.println("链接成功!!");

			/*
			*   获取连接之后可以获取执行器,执行器用来执行SQL语句
			*   主要有以下两种执行器
			*   Statement
			*   PreparedStatement
			* */
			Statement st = con.createStatement();

			String dml1 = "insert into person values (null,'测试1','12345',30,2000.00,'2000-03-03')";
			String dql1 = "select * from person";

			/*
			*   获取执行器之后可以根据SQL语句类型的不同,调用以下几种方法
			*
			*   1)   boolean        execute()
			*                       如果执行DQL语句,则返回true
			*                       如果执行DML语句,则返回false,但是依然可以执行
			*                       此方法使用较少
			*
			*   2)   int            executeUpdate()
			*                       如果执行DQL语句,立刻报错
			*                       如果执行DML语句,则返回更改的记录数
			*
			*   3)   ResultSet      executeQuery()
			*                       如果执行DML语句,立刻报错
			*                       执行DQL语句返回一个结果集ResultSet,通过解析这个结果集,可以拿取封装在里面的值
			*
			*
			*   4)   int[]          executeBatch()
			*                       执行批处理,一次执行多条SQL语句
			* */
			//int count = st.executeUpdate(dml1);
			//System.out.println(count);

			ResultSet rs = st.executeQuery(sql1);
			/*
			*   要进行解析之前,首先判断是否存在有效数据,如果没有有效数据,则不需要进行任何解析
				不要根据ResultSet是否为null,来判断是否存在有效数据,因为ResultSet类似一个表格
				存在表头,永远不为null

				存在一个 boolean next() 结果集类似一个表格,默认指针指向第一行表头,当我们调用
				.next()时,如果指针可以下移,返回true,如果不存在有效数据了,则指针无法下移一行,返回false
				所以我们可以根据.next()方法是否返回true来判断是否存在有效数据
			* */
			while(rs.next()){
				/*
				*   拿取数据:
				*       get数据类型(列数)或者get数据类型(列名)
				* */
				/*System.out.println("ID:"+rs.getInt(1)+"\t姓名:"+rs.getString(2)
				+"\t密码:"+rs.getString(3)+"\t年龄:"+rs.getInt(4)+"\t薪资:"
				+rs.getDouble(5)+"\t生日:"+rs.getDate(6));*/
				System.out.println("ID:"+rs.getInt("id")+"\t姓名:"
				+rs.getString("name")+"\t密码:"+rs.getString("pass")
				+"\t年龄:"+rs.getInt("age")+"\t薪资:"+rs.getDouble("salary")
				+"\t生日:"+rs.getDate("birth"));
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
}

1. 注意点

  1. 创建执行器
  • 通常有两种 Statement , PreparedStatement
返回类型执行器方法解释
booleanexecute()如果执行DML语句则返回true
如果执行DML语句,则返回false,但是依然可以执行
此方法使用较少
intexecuteUpdate()如果执行DQL语句立即报错
执行DML语句则返回受影响的记录数
ResultSetexecuteQuery()如果执行DML语句立即报错
执行DQL语句返回一个结果集ResultSet,通过解析这个结果集,可以拿取封装在里面的值
int[]executeBatch()执行批处理,一次执行多条SQL语句
语言全称包含内容
SQLStructured Query Language,结构化查询语言DDL、DML、DQL、DCL、TCL
DDLData Definetion Language,数据定义语言create(新建)、alter(修改)、drop(删除)、truncate(截断)
DMLData Manipulation Language,数据操纵语言insert (插入)、update(修改)、delete(删除)
DQLData Query Language,数据查询语言select(查询)
DCLData Control Language数据控制语言grant(授权)、revoke(取消授权)
TCLTranslation Control Language事务控制语言commit(提交)、rollback(回滚)、savepoint(保存还原点),只会影响DML操作。
  1. 拿取有效数据

要进行解析之前,首先判断是否存在有效数据,如果没有有效数据,则不需要进行任何解析

不要根据ResultSet是否为null,来判断是否存在有效数据,因为ResultSet类似一个表格, 存在表头,永远不为null, 存在一个 boolean next() 结果集类似一个表格,

默认指针指向第一行表头,当我们调用 rs .next() 时,如果指针可以下移,返回true,如果不存在有效数据了,则指针无法下移一行,返回false所以我们可以根据.next()方法是否返回true来判断是否存在有效数据

rs = st.executeQuery(sql);
while(rs.next()){
    //TODO
}
  1. 拿取数据
  • 可以通过 get数据类型(列数) 或者 get数据类型(列名)来拿取
Integer id = rs.getInt(1);
String name = rs,getString("name");

2.执行器的executeBatch()方法

  • 首先需要关闭mysql的自动提交事务,conn.setAutoCommit(false); 出错时不会提交
  • 用 addBatch(sql)方法 把要执行的SQL语句挨个放进执行器中
  • 执行方法并提交
  • 打开MySQL的自动提交
public class TestBatch {
	public static void main(String[] args) {
		try {
			//获取连接
			Connection con = Factory.getCon();
			//关闭mysql的自动提交事务
			con.setAutoCommit(false);
			//获取执行器
			Statement st = con.createStatement();

			//设置要批处理得sql
			//注意批处理不能执行dql语句
			String dml1 = "insert into person values (null,'elena','12345',30,5000.00,'1990-03-01')";

			String dml2 = "insert into person values (null,'damon','33345',20,6000.00,'1993-03-01')";

			String dml3 = "insert into person values (null,'stefan','53345',17,4000.00,'1992-03-01')";

			String dml4 = "delete from person where id = 1";

			//将要执行的sql语句添加进缓存中
			//这里每条sql语句都类似一个子弹,此处压入弹夹
			st.addBatch(dml1);
			st.addBatch(dml2);
			st.addBatch(dml3);
			st.addBatch(dml4);

			//进行批处理操作
			/*
			*   返回的是一个int类型的数组,内部封装了更改的记录数
			*
			* */
			int[] count = st.executeBatch();
			//提交事务
			con.commit();
			//恢复自动提交
			con.setAutoCommit(true);

			for(int i:count){
				System.out.println("更改的记录数是~~~~》"+i);
			}

		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
}

5. 🐴Statement和PreparedStatement的区别

  1. 相同点

两者都为接口

public interface Statement implements Wrapper
public interface PreparedStatement implements Statement PreparedStatement是Statement的子类

  1. 不同点

①:Statem只能执行静态语句; PreparedStatement 可以还行IN参数的sql语句,所谓IN参数是指,sql语句可以进行字段等数据的更改
并不是一个固定的语句。

②PreparedStatement存在一个强大缓存区,可以对sql语句
进行预编译,在执行相同的sql语句时,PreparedStatement
将语句加载进缓存区,仅仅编译一次,当第二次执行此语句时
不需要再次进行编译,也就是说相同的sql语句执行多条
仅仅编译一次,PreparedStatement仅对改动数据进行修改
而不再进行编译;
Statement只要语句发生了改变,则必须重新进行编译

③:PreparedStatement支持对sql语句使用?占位符,从而对
sql语句进行字段参数的修改,降低了开发难度,并且从根本上杜绝了
sql注入安全隐患

④如果sql语句不需要多次执行,或者?过多,则效率可能较
Statement低

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值