JDBC干货三

2019-12-31 14:46:01 浏览数 (1)

文章目录

  1. 1. JDBC干货三
    1. 1.1. 生成get,set方法的快捷键
    2. 1.2. eclipse中生成toString方法的快捷键
    3. 1.3. 数据库操作和对象的关系
    4. 1.4. JavaBean
    5. 1.5. Statement和PreparedStatement应用场景
    6. 1.6. 实例
      1. 1.6.1. JavaBean对象
      2. 1.6.2. crud操作
    7. 1.7. 批量操作
      1. 1.7.1. Statement执行批量操作
      2. 1.7.2. PreparedStatement
        1. 1.7.2.1. 批量插入数据
        2. 1.7.2.2. 分页查询
    8. 1.8. 事务
      1. 1.8.1. ACID
      2. 1.8.2. jdbc操作事务
    9. 1.9. 获取自增主键的值
      1. 1.9.1. 准备sql
    10. 1.10. 获取元数据
    11. 1.11. 乱码问题

JDBC干货三

生成get,set方法的快捷键

  1. alt shift s
  2. r
  3. alt a a松手 alt不松手 按o 最后回车

eclipse中生成toString方法的快捷键

  • alt shift o 回车

数据库操作和对象的关系

  • 因为数据库中查询的数据比较零散,需要通过对象的形式把数据封装起来
  • 这种封装数据的对象通常称为javaBean
  • 以后项目开发,基本上有什么表在代码中就会创建相应的对象,表中有什么字段,对象中就有什么属性

JavaBean

  • 俗称简单的java对象

-具备如下的三个特点

代码语言:javascript复制
- 私有属性
- 无参构造
- 为属性提供get,set方法

Statement和PreparedStatement应用场景

  • 通常DDL使用Statement
  • 通常DML 和DQL使用PreparedStatement
  • 只有需要传入参数的就要使用PreparedStatent

实例

  • 我们将数据库中的表和JavaBean相对应实现了crud操作
  • 使用了PreparedStatement对象操作数据库

JavaBean对象

代码语言:javascript复制
public class Item {
	private int id;
	private String title;
	private int price;
	private int num;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public int getPrice() {
		return price;
	}
	public void setPrice(int price) {
		this.price = price;
	}
	public int getNum() {
		return num;
	}
	public void setNum(int num) {
		this.num = num;
	}
	@Override
	public String toString() {
		return "Item [id="   id   ", title="   title   ", price="   price
				  ", num="   num   "]";
	}


}

crud操作

  • 传入的参数全部都是JavaBean对象
  • 其中的sql语句不能有中的占位符部分不能有空格,否则可能会出现错误
  • 这里使用的是前一篇讲的数据库工具类终结版(使用了DBCP连接池),详情请看前一篇的文章
代码语言:javascript复制
// 插入数据,传入JavaBean对象作为参数
	public void insert(Item item) {
		Connection connection = null;
		PreparedStatement statement = null; // 创建预处理对象
		ResultSet resultSet = null;
		try {
			connection = DBUtils.getConnection(); // 获取连接
			String sql = "insert into t_item(id,title,price,num) values(?,?,?,?)";
			statement = connection.prepareStatement(sql);
			statement.setInt(1, item.getId());
			statement.setString(2, item.getTitle()); // 为预处理对象中的占位符赋值
			statement.setInt(3, item.getPrice());
			statement.setInt(4, item.getNum());
			int row = statement.executeUpdate();
			System.out.println(row);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			DBUtils.close(connection, statement, resultSet); // 关闭资源
		}
	}

	// 查询数据,封装在JavaBean中
	public List<Item> findAll() {
		ArrayList<Item> items = new ArrayList<Item>();
		Connection connection = null;
		PreparedStatement statement = null; // 创建预处理对象
		ResultSet resultSet = null;
		try {
			connection = DBUtils.getConnection(); // 获取连接
			String sql = "select * from t_item where price>100";
			statement = connection.prepareStatement(sql);
			resultSet = statement.executeQuery();
			while (resultSet.next()) {
				String title = resultSet.getString("title");
				int price = resultSet.getInt("price");
				int num = resultSet.getInt("num");

				Item item = new Item();
				item.setNum(num);
				item.setPrice(price);
				item.setTitle(title);
				items.add(item);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			DBUtils.close(connection, statement, resultSet); // 关闭资源
		}
		return items;
	}

	//更新操作,传入JavaBean对象,只需要将要更新的条件封装进去即可
	public void update(Item item) {
		Connection connection = null;
		PreparedStatement statement = null; // 创建预处理对象
		ResultSet resultSet = null;
		try {
			connection = DBUtils.getConnection(); // 获取连接
			String sql = "update  t_item set title=?,num=?,price=? where id=?";
			statement = connection.prepareStatement(sql);
			//设置其中的占位符的值
			statement.setString(1, item.getTitle());
			statement.setInt(2, item.getNum());
			statement.setInt(3, item.getPrice());
			statement.setInt(4, item.getId());
			int row = statement.executeUpdate();
			System.out.println(row);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			DBUtils.close(connection, statement, resultSet); // 关闭资源
		}
	}

	// 删除的数据,其中参数传入的还是JavaBean对象
	public void delete(Item item) {
		Connection connection = null;
		PreparedStatement statement = null; // 创建预处理对象
		ResultSet resultSet = null;
		try {
			connection = DBUtils.getConnection(); // 获取连接
			String sql = "delete from t_item where id=?";
			statement = connection.prepareStatement(sql);
			statement.setInt(1, item.getId());
			int row = statement.executeUpdate();
			System.out.println(row);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			DBUtils.close(connection, statement, resultSet); // 关闭资源
		}
	}

批量操作

  • 因为类似的sql语句执行,每一个次都需要和数据库服务器进行数据交互,多次交互会浪费资源,并且耗时,可以使用批量

Statement执行批量操作

  • 需要写多个重复的sql语句,只是其中的想用批量的内容不同,比较繁琐 -最后将这些sql语句中添加到批量操作中
    • statement.addBatch(sql);
  • 添加到批量操作之后,就开始执行批量方法了
    • statement.executeBatch();
代码语言:javascript复制
@Test
public void testStatement() {
	Connection connection = null;
	Statement statement = null;
	ResultSet resultSet = null;
	try {
		connection = DBUtils.getConnection(); // 获取连接
		statement = connection.createStatement(); // 创建Statement语句对象
		String sql1 = "insert into t_item(id,title) values(100,'asaa')";
		String sql2 = "insert into t_item(id,title) values(101,'asaa')";
		String sql3 = "insert into t_item(id,title) values(102,'asaa')";

		// 添加批量操作
		statement.addBatch(sql1);
		statement.addBatch(sql2);
		statement.addBatch(sql3);
		// 执行批量操作
		statement.executeBatch();
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		DBUtils.close(connection, statement, resultSet); // 关闭资源
	}
}

PreparedStatement

  • 只需要写一个条sql语句,其中要批量的内容使用占位符即可
  • 设置占位符的内容,将其添加到批量中,再重新设置,这样的好处就是减少了重复的sql语句了
    • statement.addBatch()
  • 最后直接执行批量操作即可
    • statement.executeBatch();
代码语言:javascript复制
@Test
public void testPreparedStatement() {
	Connection connection = null;
	PreparedStatement statement = null;
	ResultSet resultSet = null;
	try {
		connection = DBUtils.getConnection(); // 获取连接
		String sql = "insert into t_item(id,title) values(?,?)";

		statement = connection.prepareStatement(sql);
		statement.setInt(1, 200);
		statement.setString(2, "联想电脑");
		statement.addBatch(); // 添加上面的数据到Batch中

		statement.setInt(1, 201);
		statement.setString(2, "华硕笔记本");
		statement.addBatch(); // 添加上面的数据到Batch中

		statement.setInt(1, 202);
		statement.setString(2, "海尔洗衣机");
		statement.addBatch(); // 添加上面的数据到Batch中

		statement.executeBatch(); // 执行批量操作

	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		DBUtils.close(connection, statement, resultSet); // 关闭资源
	}

}
批量插入数据
  • 注意:addBatch()其中的数量是有限的,如果存放的批量操作太多,那么会造成内存溢出,因此我们应该当其中批量操作的数量达到一定值的时候先执行一次,然后清除执行完的操作即可(clearBatch())
  • 批量操作的时候如果批量操作的数量太多的话,肯定会造成内存溢出,这个时候最好的办法就是当数量达到一定数量时候就执行,然后将其中的已经执行完成的清除即可
  • 下面是向表中插入有100条数据,我们每20条插入一次,这样就可以避免内存的溢出
代码语言:javascript复制
@Test
public void test1(){
	Connection connection = null;
	PreparedStatement statement = null;
	ResultSet resultSet = null;
	try {
		connection = DBUtils.getConnection(); // 获取连接
		String sql = "insert into t_v(name) values(?)";
		statement=connection.prepareStatement(sql);
		for(int i=0;i<100;i  ){
			statement.setString(1, "name" (i 1));
			statement.addBatch();
			//为了避免内存溢出,当批量操作数量达到一定值时先执行一次,在向其中添加
			//每二十次添加一次
			if (i ==0) {
				statement.executeBatch();   //执行批量操作
				statement.clearBatch();  //清除已经执行过的
			}
			statement.executeBatch();   //为了避免有剩余的,把剩下的执行掉
		}
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		DBUtils.close(connection, statement, resultSet); // 关闭资源
	}
}
分页查询
  • 要求: 在控制台输入页数(n),和每页显示的数量(m)
  • 分析: 我们知道sql语句中的limit ?,?,第一个参数表示的是跳过的条数,第二个参数是每页显示的条数,那么此时我们限定显示第n页,每页显示m条,那么此时的跳过的条数就是(n-1)*m,因此此时的查询语句就是: select * from table_name limit (n-1)*m,m;
  • 代码如下:
代码语言:javascript复制
@Test
public void testLimit(){
	Connection connection = null;
	PreparedStatement statement = null;
	ResultSet resultSet = null;
	Scanner scanner=new Scanner(System.in);   //控制台输入
	try {
		connection = DBUtils.getConnection(); // 获取连接
		String sql = "select * from t_v limit ?,?";
		statement=connection.prepareStatement(sql);

		// n页,每页m条    limit (n-1)*m m
		System.out.println("第几页:");
		int n=Integer.parseInt(scanner.nextLine());   //页数,控制台读取的是字符串,因此这里需要转换
		System.out.println("每页的条数");
		int m=Integer.parseInt(scanner.nextLine());   //每页显示的条数

		//设置占位符
		statement.setInt(1, (n-1)*m);
		statement.setInt(2, m);
		//查询,获取结构集
		resultSet=statement.executeQuery();
		//遍历结果集
		while(resultSet.next()){
			int id=resultSet.getInt("id");   //获取id
			String name=resultSet.getString("name");  //获取name
			System.out.println(id "-----" name "t");   //制表符输出值
		}
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		DBUtils.close(connection, statement, resultSet); // 关闭资源
	}
}

事务

ACID

  • 原子性
  • 一致性
  • 隔离性
  • 持久性

jdbc操作事务

  • connection.setAutoCommit(false) 关闭自动提交 如果不关闭自动提交,那么会每执行一行都会提交一次
  • connection.commit() 提交
  • connection.rollback() 回滚
  • 转账的实现过程
    • 创建表:create table user(id int,name,varchar(10),money int);
    • 插入数据:insert into user values(1,'超人',200),(2,'蝙蝠侠',10000);
    • 关闭自动提交 connection.setAutoCommit(false)
    • 修改超人的钱(money 3000)
    • 修改蝙蝠侠的钱(money-3000)
    • 查询蝙蝠侠的钱是否大于0,如果小于0,则抛出运行时异常,大于0 提交(commit)
    • 在catch异常的地方把SQLException改成Exception,并且在catch里面回滚
代码语言:javascript复制
@Test
public void testTransaction() {
	Connection connection = null;
	PreparedStatement statement = null;
	ResultSet resultSet = null;
	try {
		connection = DBUtils.getConnection(); // 获取连接
		connection.setAutoCommit(false); // 关闭自动提交
		String sql = "update user set money=money ? where id=?"; // 修改蝙蝠侠和超人钱的sql语句
		String sql_select = "select money from user where id=?"; // 查询钱

		// 创建更新的预编译对象
		statement = connection.prepareStatement(sql);

		// 超人 3000
		statement.setInt(1, 3000);
		statement.setInt(2, 1);
		int row1 = statement.executeUpdate(); // 执行更新语句

		// 蝙蝠侠-3000
		statement.setInt(1, -3000);
		statement.setInt(2, 2);
		int row2 = statement.executeUpdate(); // 执行更新语句

		// 预编译查询sql语句
		statement = connection.prepareStatement(sql_select);

		statement.setInt(1, 2);

		resultSet = statement.executeQuery(); // 执行查询语句
		while (resultSet.next()) {
			int money = resultSet.getInt("money"); // 获取蝙蝠侠的此时的钱
			// 如果<0 抛出运行异常
			if (money < 0) {
				throw new RuntimeException(); // 手动抛出异常
			} else { // 如果 >0 可以成功提交
				connection.commit(); // 提交
			}
		}
	} catch (Exception e) {
		e.printStackTrace();
		try {
			connection.rollback(); // 回滚,如果运行出错,那么就回滚到起始点,数据库中就不会生效
		} catch (SQLException e1) {
			e1.printStackTrace();
		}
	} finally {
		DBUtils.close(connection, statement, resultSet); // 关闭资源
	}
}

获取自增主键的值

  • 为什么获取: 因为某些插入的数据,插入完之后,需要用到数据的主键作为下一条数据外键

准备sql

  • create table t_d(id int primary key auto_increment,name varchar(10));
代码语言:javascript复制
@Test
public void testAuto() {
	Connection connection = null;
	Statement statement = null;
	ResultSet resultSet = null;
	try {
		connection = DBUtils.getConnection(); // 获取连接
		String sql="insert into t_d values(null,'神仙')";
		statement=connection.createStatement();
		//执行sql,并且标记此时执行需要获取生成的key值
		statement.executeUpdate(sql,Statement.RETURN_GENERATED_KEYS);
		//得到生成的key值
		resultSet=statement.getGeneratedKeys();
		while(resultSet.next()){
			int id=resultSet.getInt(1);   //获取第一个值,不能写getInt("id") 因为这里不是查询得到的数据,字段名并不是id
			System.out.println("自增主键的值为:" id);
		}
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		DBUtils.close(connection, statement, resultSet); // 关闭资源
	}
}

获取元数据

  • 数据库元数据: 数据库厂商信息(mysql,oracle) 数据库连接信息,都称为数据库的元数据
  • 表元数据
代码语言:javascript复制
@Test
public void testMetaData() {
	Connection connection = null;
	Statement statement = null;
	ResultSet resultSet = null;
	try {
		connection = DBUtils.getConnection(); // 获取连接
		statement=connection.createStatement();
		//得到数据库元数据
		DatabaseMetaData data=connection.getMetaData();
		System.out.println(data.getDriverName());  //数据库驱动名字
		System.out.println(data.getDriverVersion());  //驱动版本
		System.out.println(data.getUserName());  //用户名
		System.out.println(data.getURL());  //连接地址
		System.out.println(data.getDatabaseProductName());  //数据库厂商的名称

		String sql="select * from t_d";
		resultSet=statement.executeQuery(sql);
		//从结果集中获取表的元数据
		ResultSetMetaData sqldata=resultSet.getMetaData();
		int columcount=sqldata.getColumnCount();  //获取表字段的数量

		//获取表中每个字段的名称
		for(int i=0;i<columcount;i  ){
			String name=sqldata.getColumnName(i 1);
			System.out.println("字段名:" name "t");
		}

	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		DBUtils.close(connection, statement, resultSet); // 关闭资源
	}
}

乱码问题

  • 在JDBC连接数据的url后面添加如下参数:
    • jdbc:mysql://localhost:3306/test?UseUnicode=true&characterEncoding=UTF-8

0 人点赞