DAO (Data Access Object)数据访问对象
位于业务逻辑层 和 数据库之间,实现对持久化数据的访问
ORM 对象关系映射
将关系型数据的表映射为对象,方便以面向对象思想开发
Statement 接口
PreparedStatement 预编译语句 防止sql拼接错误
MySQL不支持预编译池,Oracle支持
可以防止SQL注入 内部将非法字符进行了转义 如将 ' 转义为 \'
调用带有参数和返回值的存储过程
Connection conn = JdbcUtil.getConn();
CallableStatement stCall = conn.prepareCall("call getNameById(?,?);");
stCall.setInt(1, 1);
stCall.registerOutParameter(2, Types.VARCHAR);
stCall.execute();
String name = stCall.getString(2);
System.out.println(name);
JdbcUtil.close(conn, stCall, null);
事务模拟银行转账
//是否有钱
Connection conn = JdbcUtil.getConn();
String sql = "select * from account where name=? and money>?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, "lisi");
ps.setInt(2, 1000);
ResultSet rs = ps.executeQuery();
if (!rs.next()) {
throw new RuntimeException("余额不足!");
}
try {
//设置事务
conn.setAutoCommit(false);
//李四 扣除钱
sql = "update account set money=money-? where name=? ";
ps = conn.prepareStatement(sql);
ps.setDouble(1, 1000);
ps.setString(2, "lisi");
ps.executeUpdate();
int a = 1/0; //模拟断电等异常
//刘五 增加钱
sql = "update account set money=money+? where name=? ";
ps = conn.prepareStatement(sql);
ps.setDouble(1, 1000);
ps.setString(2, "liuwu");
ps.executeUpdate();
//提交事务
conn.commit();
System.out.println("转账成功");
} catch (Exception e) {
e.printStackTrace();
//出现异常时进行事务回滚
conn.rollback();
} finally {
//释放资源
JdbcUtil.close(conn, ps, rs);
}
}
批处理
一次性执行多条sql 语句,比单独提交处理效率高
普通插入
Connection conn = JdbcUtil.getConn();
String sql = "INSERT INTO stu(name,age) VALUES(?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
long begin = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
ps.setString(1, "李狗蛋");
ps.setInt(2, 30);
ps.executeUpdate(); //一次执行一个。
}
long end = System.currentTimeMillis();
long time = end - begin;
System.out.println(time);
JdbcUtil.close(conn, ps, null);
批量处理进行插入
Connection conn = JdbcUtil.getConn();
String sql = "INSERT INTO stu(name,age) VALUES(?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
long begin = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
ps.setString(1, "李狗蛋");
ps.setInt(2, 30);
//加入批处理
ps.addBatch();
}
//执行批处理 MySQL 默认不进行批处理,需要在连接数据时url后面添加 rewriteBatchedStatements=true;
ps.executeBatch();
long end = System.currentTimeMillis();
long time = end - begin;
System.out.println(time);
JdbcUtil.close(conn, ps, null);
存储图片
可以已二进制流的形式存储 图片 音频 视频等 BLOB
然而 实际开发中不可能这样做的,实际存储的是文件存储路径。
//向数据库写入图片
Connection conn = JdbcUtil.getConn();
String sql = "insert into student(name,image) values(?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
FileInputStream in = new FileInputStream("E:/mm.jpg");
ps.setString(1, "橘子");
ps.setBlob(2, in);
ps.executeUpdate();
JdbcUtil.close(conn, ps, null);
//从数据库获取图片
Connection conn = JdbcUtil.getConn();
String sql = "select * from student";
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
//获取图片
Blob blob = (Blob) rs.getBlob("image");
//获取图片的二进制 输入流
InputStream in = blob.getBinaryStream();
//将输入流 写到磁盘
Files.copy(in, Paths.get("E:/pp.png"));
}
JdbcUtil.close(conn, ps, rs);
插入时获取主键
Connection conn = JdbcUtil.getConn();
String sql = "insert into stu(name,age) values(?,?)";
PreparedStatement ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
ps.setString(1, "小红");
ps.setInt(2, 20);
ps.executeUpdate();
ResultSet rs = ps.getGeneratedKeys();
if (rs.next()) {
int id = rs.getInt(1);
System.out.println(id);
}
JdbcUtil.close(conn, ps, rs);
数据库连接池
保存数据库连接对象的容器。优点:消除对象创建所带来的延迟,提高系统性能。
为数据库的连接建立一个缓冲池,预先在存放一定数量的连接,
需要建立连接时,取出一个,使用完毕后再放回去,
可以通过设置连接池最大连接数来防止系统无尽的与数据库连接
可以通过连接池的管理机制监视数据库的连接数量,使用情况,为系统开发,测试及性能调整提供依据。
连接池中的属性:
- 连接数据库需要的4个要素,驱动名称,数据库地址,用户名,密码
- 初始化连接数,初始化时,连接池当中创建多少个连接对象
- 最大连接数 连接池当中最多存储多少个连接对象
- 最小连接数 连接池当中最少存储多少个连接对象
- 最大空闲时间 如果获取了一个连接对象,指定时间内没有任何动作,就会自动释放
- 最大等待时间 指定时间内,尝试获取连接,超出时间,就会提示获取失败
java 中连接池是使用javax.sql .DataSource接口来表示。
DataSource和jdbc一样,也是只是提供了一个接口,由第三方组织实现。
常见的数据库连接池有
- DBCP spring 推荐,Tomcat的数据源使用的就是DBCP
- C3P0 是hibernate推荐的 基本上不用。从07年不更新了
- Druid 阿里巴巴提供的连接池 号称最好的连接池。
获取方式不同:
- 传统:Connection conn = DriverManager.getConnection(url,username,pswd);
- 连接池: Connection conn = DataSource对象.getConnection();
释放资源不同 - 传统:conn.close();
- 连接池 把数据库连接对象还给连接池。
DBCP 使用
// 使用DBCP连接池
public static String driverName = "com.mysql.jdbc.Driver";
public static String url = "jdbc:mysql://localhost:3306/test_jdbc?rewriteBatchedStatements=true";
public static String user = "root";
public static String password = "123";
public static BasicDataSource ds = null;
static{
ds = new BasicDataSource();
ds.setDriverClassName(driverName);
ds.setUrl(url);
ds.setUsername(user);
ds.setPassword(password);
}
/**
* 获取连接对象
* @return
*/
public static Connection getConn() {
try {
Connection connection = ds.getConnection();
return connection;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Druid 使用
创建db.properties配置文件
driverName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test_jdbc?rewriteBatchedStatements=true
username=root
password=123
创建数据库连接工具类
public static DataSource ds = null;
static {
try {
// 读取配置文件
Properties p = new Properties();
FileInputStream in = new FileInputStream("resource/db.properties");
p.load(in);
ds = DruidDataSourceFactory.createDataSource(p);
} catch (Exception e) {
}
}
private void DruidUtil() {
}
public static Connection getConn() throws IOException, SQLException{
return ds.getConnection();
}
/**
* 释放资源
* @param conn
* @param st
* @param rs
*/
public static void close(Connection conn, Statement st, ResultSet rs) {
if (rs !=null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (st != null) {
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
中文乱码 useUnicode=true&characterEncoding=utf-8
url=jdbc:mysql://localhost:3306/mystore?useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true
网友评论