文章目录
- 1. JDBC干货三
- 1.1. 生成get,set方法的快捷键
- 1.2. eclipse中生成toString方法的快捷键
- 1.3. 数据库操作和对象的关系
- 1.4. JavaBean
- 1.5. Statement和PreparedStatement应用场景
- 1.6. 实例
- 1.6.1. JavaBean对象
- 1.6.2. crud操作
- 1.7. 批量操作
- 1.7.1. Statement执行批量操作
- 1.7.2. PreparedStatement
- 1.7.2.1. 批量插入数据
- 1.7.2.2. 分页查询
- 1.8. 事务
- 1.8.1. ACID
- 1.8.2. jdbc操作事务
- 1.9. 获取自增主键的值
- 1.9.1. 准备sql
- 1.10. 获取元数据
- 1.11. 乱码问题
JDBC干货三
生成get,set方法的快捷键
- alt shift s
- r
- 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连接池),详情请看前一篇的文章
// 插入数据,传入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();
@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();
@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条插入一次,这样就可以避免内存的溢出
@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;
- 代码如下:
@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里面回滚
- 创建表:
@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));
@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) 数据库连接信息,都称为数据库的元数据
- 表元数据
@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