控制层: servLet相应服务器端请求。 服务层:service/BIz 数据层:DAO
1.JDBC常规操作:
1.JDBC:sun发布的一个java程序和数据库之间通信的规范(接口) 2.各大数据库厂商去实现JDBc规范(实现类),这些实现类打成压缩包,就是所谓的jar包
1).JDBC连接MYSQL数据库
安装mysql,创建数据库fruitdb idea引入jdbcJar包
package com.atguigu.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class demo01 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Class.forName("org.gjt.mm.mysql.Driver");
String url = "jdbc:mysql://localhost:3306/fruitdb";
String user = "root";
String pwd = "123456";
Connection conn = DriverManager.getConnection(url, user, pwd);
System.out.println("conn = " + conn);
}
}
2).JDBC对数据库进行增、删、改
package com.atguigu.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Demo02 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/fruitdb?usrSSL=falseuse&Unicode=true&characterEncoding=utf8", "root", "123456");
String sql = "insert into t_fruit values(0,?,?,?,?)";
PreparedStatement psmt = conn.prepareStatement(sql);
psmt.setString(1,"榴莲");
psmt.setInt(2,15);
psmt.setInt(3,100);
psmt.setString(4,"榴莲是一种神器的水果");
int count = psmt.executeUpdate();
System.out.println(count > 0 ? "execced": "failed");
psmt.close();
conn.close();
}
}
package com.atguigu.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Demo04 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Class.forName("org.gjt.mm.mysql.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/fruitdb?useUnicode=true&characterEncoding=utf-8&useSSL=false","root","123456");
String sql = "delete from t_fruit where fid = ? " ;
PreparedStatement psmt = conn.prepareStatement(sql);
psmt.setInt(1,6);
int count = psmt.executeUpdate();
System.out.println(count > 0 ? "删除成功!" : "删除失败!");
psmt.close();
conn.close();
}
}
3).JDBC对数据库进行查询操作
package com.atguigu.jdbc;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class Demo05 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Class.forName("org.gjt.mm.mysql.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/fruitdb?useUnicode=true&characterEncoding=utf-8&useSSL=false","root","123456");
String sql = "select * from t_fruit" ;
PreparedStatement psmt = conn.prepareStatement(sql);
ResultSet rs = psmt.executeQuery();
List<Fruit> fruitList = new ArrayList<>();
while(rs.next()){
int fid = rs.getInt(1);
String fname = rs.getString("fname");
int price = rs.getInt(3);
int fcount = rs.getInt(4);
String remark = rs.getString(5);
Fruit fruit = new Fruit(fid , fname , price , fcount , remark );
fruitList.add(fruit);
}
rs.close();
psmt.close();
conn.close();
fruitList.forEach(System.out::println);
}
}
4).添加操作时获取自增列主键值
protected int executeUpdate(String sql , Object... params){
boolean insertFlag = false ;
insertFlag = sql.trim().toUpperCase().startsWith("INSERT");
try {
conn = getConn();
if(insertFlag){
psmt = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
}else {
psmt = conn.prepareStatement(sql);
}
setParams(psmt,params);
int count = psmt.executeUpdate() ;
rs = psmt.getGeneratedKeys();
if(rs.next()){
return ((Long)rs.getLong(1)).intValue();
}
return count ;
} catch (SQLException e) {
e.printStackTrace();
}finally {
close(rs,psmt,conn);
}
return 0;
}
5).批处理
package com.atguigu.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Arrays;
public class Demo01Batch {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/fruitdb?useSSL=false&useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true","root","123456");
String sql = "insert into t_fruit values(0,?,?,?,?)";
PreparedStatement psmt = conn.prepareStatement(sql);
for(int i = 0 ; i<10 ; i++){
psmt.setString(1,"榴莲"+i);
psmt.setInt(2,15);
psmt.setInt(3,100);
psmt.setString(4,"榴莲是一种神奇的水果");
psmt.addBatch();
if(i%1000==0){
psmt.executeBatch();
psmt.clearBatch();
}
}
int[] count = psmt.executeBatch();
for (int i = 0; i < count.length; i++) {
System.out.println(count[i]);
}
psmt.close();
conn.close();
}
}
2.项目实战-水果库存系统
2.1 需求介绍
水果库存系统的需求:
=================欢迎使用水果库存系统=====================
1.查看水果库存列表
2.添加水果库存信息
3.查看特定水果库存信息
4.水果下架
5.退出
======================================================
请选择: 1
------------------------------------------------------
FID 名称 单价 库存 备注
1 苹果 5 100 苹果很好吃
2 西瓜 3 55 西瓜很好吃
3 榴莲 15 99 榴莲是一种神奇的水果
------------------------------------------------------
或者
------------------------------------------------------
FID 名称 单价 库存 备注
对不起,库存为空!
------------------------------------------------------
=================欢迎使用水果库存系统=====================
1.查看水果库存列表
2.添加水果库存信息
3.查看特定水果库存信息
4.水果下架
5.退出
======================================================
请选择:2
请输入水果名称:苹果
请输入追加的库存量:30
添加成功!
=================欢迎使用水果库存系统=====================
1.查看水果库存列表
2.添加水果库存信息
3.查看特定水果库存信息
4.水果下架
5.退出
======================================================
请选择:1
------------------------------------------------------
FID 名称 单价 库存 备注
1 苹果 5 130 苹果很好吃
2 西瓜 3 55 西瓜很好吃
3 榴莲 15 99 榴莲是一种神奇的水果
------------------------------------------------------
=================欢迎使用水果库存系统=====================
1.查看水果库存列表
2.添加水果库存信息
3.查看特定水果库存信息
4.水果下架
5.退出
======================================================
请选择:2
请输入水果名称:番茄
请输入水果单价:6
请输入水果库存量:90
请输入水果备注:番茄也是水果
添加成功!
=================欢迎使用水果库存系统=====================
1.查看水果库存列表
2.添加水果库存信息
3.查看特定水果库存信息
4.水果下架
5.退出
======================================================
请选择:3
请输入水果名称:菠萝蜜
对不起,没有找到指定的水果库存记录!
=================欢迎使用水果库存系统=====================
1.查看水果库存列表
2.添加水果库存信息
3.查看特定水果库存信息
4.水果下架
5.退出
======================================================
请选择:3
请输入水果名称:西瓜
------------------------------------------------------
FID 名称 单价 库存 备注
2 西瓜 3 55 西瓜很好吃
------------------------------------------------------
=================欢迎使用水果库存系统=====================
1.查看水果库存列表
2.添加水果库存信息
3.查看特定水果库存信息
4.水果下架
5.退出
======================================================
请选择:4
请输入水果名称:菠萝蜜
对不起,没有找到需要下架的水果库存记录!
=================欢迎使用水果库存系统=====================
1.查看水果库存列表
2.添加水果库存信息
3.查看特定水果库存信息
4.水果下架
5.退出
======================================================
请选择:4
请输入水果名称:苹果
是否确认下架?(Y/N) Y
下架成功!
=================欢迎使用水果库存系统=====================
1.查看水果库存列表
2.添加水果库存信息
3.查看特定水果库存信息
4.水果下架
5.退出
======================================================
请选择:5
是否确认退出?(Y/N) Y
谢谢使用!再见!
2.2 显示主菜单
menu.java
public int showMainMenu(){
System.out.println("=================欢迎使用水果库存系统=====================");
System.out.println("1.查看水果库存列表");
System.out.println("2.添加水果库存信息");
System.out.println("3.查看特定水果库存信息");
System.out.println("4.水果下架");
System.out.println("5.退出");
System.out.println("======================================================");
System.out.print("请选择:");
int slt = input.nextInt();
return slt ;
}
2.3 退出
menu.java
public boolean exit(){
System.out.print("是否确认退出?(Y/N)");
String slt = input.next();
return !"Y".equalsIgnoreCase(slt);
}
2.4 DAO的概念以及DAO的设计
- DAO的概念和角色(设计理念): DAO-称之为数据访问对象,其中的方法都是单精度方法。
什么叫单精度,单精度指的是这个方法的粒度不能再分了,已经非常细了(因此也称之为细粒度)
package com.atguigu.fruit.dao;
import com.atguigu.fruit.pojo.Fruit;
import java.util.List;
public interface FuritDAO {
List<Fruit> getFruitList();
boolean addFruit(Fruit fruit);
boolean updateFruit(Fruit fruit);
Fruit getFruitByFname(String name);
boolean delFruit(String fname);
}
2.5 实现DAO接口
package com.atguigu.fruit.dao.impl;
import com.atguigu.fruit.dao.FruitDAO;
import com.atguigu.fruit.pojo.Fruit;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class FruitDAOImpl implements FruitDAO {
Connection conn ;
PreparedStatement psmt ;
ResultSet rs ;
final String DRIVER = "com.mysql.jdbc.Driver" ;
final String URL = "jdbc:mysql://localhost:3306/fruitdb?useUnicode=true&characterEncoding=utf-8&useSSL=false";
final String USER = "root";
final String PWD = "123456" ;
@Override
public List<Fruit> getFruitList() {
List<Fruit> fruitList = new ArrayList<>();
try {
Class.forName(DRIVER);
conn = DriverManager.getConnection(URL, USER, PWD);
String sql = "select * from t_fruit";
psmt = conn.prepareStatement(sql);
rs = psmt.executeQuery();
while(rs.next()){
int fid = rs.getInt(1);
String fname = rs.getString(2);
int price = rs.getInt(3);
int fcount = rs.getInt(4);
String remark = rs.getString(5);
Fruit fruit = new Fruit(fid, fname , price , fcount , remark) ;
fruitList.add(fruit);
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}finally {
try {
if (rs != null) {
rs.close();
}
if(psmt!=null){
psmt.close();
}
if(conn!=null && !conn.isClosed()){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return fruitList ;
}
@Override
public boolean addFruit(Fruit fruit) {
try {
Class.forName(DRIVER);
conn = DriverManager.getConnection(URL,USER,PWD);
String sql = "insert into t_fruit values(0,?,?,?,?)";
psmt = conn.prepareStatement(sql);
psmt.setString(1,fruit.getFname());
psmt.setInt(2,fruit.getPrice());
psmt.setInt(3,fruit.getFcount());
psmt.setString(4,fruit.getRemark());
return psmt.executeUpdate() > 0 ;
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}finally {
try {
if(psmt!=null){
psmt.close();
}
if(conn!=null && !conn.isClosed()){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return false;
}
@Override
public boolean updateFruit(Fruit fruit) {
try {
Class.forName(DRIVER);
conn = DriverManager.getConnection(URL,USER,PWD);
String sql = "update t_fruit set fcount = ? where fid = ? " ;
psmt = conn.prepareStatement(sql);
psmt.setInt(1,fruit.getFcount());
psmt.setInt(2,fruit.getFid());
return psmt.executeUpdate() > 0 ;
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}finally {
try {
if(psmt!=null){
psmt.close();
}
if(conn!=null && !conn.isClosed()){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return false;
}
@Override
public Fruit getFruitByFname(String fname) {
try {
Class.forName(DRIVER);
conn = DriverManager.getConnection(URL, USER, PWD);
String sql = "select * from t_fruit where fname like ? ";
psmt = conn.prepareStatement(sql);
psmt.setString(1,fname);
rs = psmt.executeQuery();
if(rs.next()){
int fid = rs.getInt(1);
int price = rs.getInt(3);
int fcount = rs.getInt(4);
String remark = rs.getString(5);
return new Fruit(fid , fname , price , fcount , remark ) ;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
if (rs != null) {
rs.close();
}
if(psmt!=null){
psmt.close();
}
if(conn!=null && !conn.isClosed()){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return null;
}
@Override
public boolean delFruit(String fname) {
try {
Class.forName(DRIVER);
conn = DriverManager.getConnection(URL,USER,PWD);
String sql = "delete from t_fruit where fname like ? " ;
psmt = conn.prepareStatement(sql);
psmt.setString(1,fname);
return psmt.executeUpdate() > 0 ;
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}finally {
try {
if (rs != null) {
rs.close();
}
if(psmt!=null){
psmt.close();
}
if(conn!=null && !conn.isClosed()){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return false;
}
}
2.6 添加库存记录
menu
public void addFruit(){
System.out.print("请输入水果名称:");
String fname = input.next() ;
Fruit fruit = fruitDAO.getFruitByFname(fname);
if(fruit==null){
System.out.print("请输入水果单价:");
int price = input.nextInt() ;
System.out.print("请输入水果库存量:");
int fcount = input.nextInt() ;
System.out.print("请输入水果备注:");
String remark = input.next() ;
fruit = new Fruit(0,fname , price , fcount , remark ) ;
fruitDAO.addFruit(fruit);
}else{
System.out.print("请输入追加的库存量:");
int fcount = input.nextInt() ;
fruit.setFcount(fruit.getFcount()+fcount);
fruitDAO.updateFruit(fruit);
}
System.out.println("添加成功!");
}
2.7 显示库存列表
menu
public void showFruitList(){
List<Fruit> fruitList = fruitDAO.getFruitList();
System.out.println("------------------------------------------------------");
System.out.println("编号\t\t名称\t\t单价\t\t库存\t\t备注");
if(fruitList==null || fruitList.size()<=0){
System.out.println("对不起,库存为空!");
}else{
for (int i = 0; i < fruitList.size(); i++) {
Fruit fruit = fruitList.get(i);
System.out.println(fruit);
}
}
System.out.println("------------------------------------------------------");
}
client
case 2:
m.addFruit();
break;
2.8 查看指定水果库存信息
public void showFruitInfo(){
System.out.print("请输入水果名称:");
String fname = input.next() ;
Fruit fruit = fruitDAO.getFruitByFname(fname);
if(fruit==null){
System.out.println("对不起,没有找到指定的水果库存记录!");
}else{
System.out.println("------------------------------------------------------");
System.out.println("编号\t\t名称\t\t单价\t\t库存\t\t备注");
System.out.println(fruit);
System.out.println("------------------------------------------------------");
}
}
2.9 水果下架
public void delFruit(){
System.out.print("请输入水果名称:");
String fname = input.next() ;
Fruit fruit = fruitDAO.getFruitByFname(fname);
if(fruit==null){
System.out.println("对不起,没有找到需要下架的水果信息!");
}else{
System.out.print("是否确认下架?(Y/N)");
String slt = input.next() ;
if("y".equalsIgnoreCase(slt)){
fruitDAO.delFruit(fname);
System.out.println("下架成功!");
}
}
}
2.8 CLient
package com.atguigu.fruit.view;
import com.atguigu.fruit.controller.Menu;
public class Client {
public static void main(String[] args) {
Menu m = new Menu() ;
boolean flag = true ;
while(flag){
int slt = m.showMainMenu();
switch(slt){
case 1:
m.showFruitList();
break;
case 2:
m.addFruit();
break;
case 3:
m.showFruitInfo();
break;
case 4:
m.delFruit();
break;
case 5:
flag=m.exit();
break;
default:
System.out.println("你不按套路出牌!");
break;
}
}
System.out.println("谢谢使用!再见!");
}
}
3.JDBC优化
3.1 抽取连接及释放资源的方法
FruitDAOImpl
private Connection getConn(){
try {
Class.forName(DRIVER);
return DriverManager.getConnection(URL, USER, PWD);
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
return null ;
}
private void close(ResultSet rs , PreparedStatement psmt , Connection conn){
try {
if (rs != null) {
rs.close();
}
if(psmt!=null){
psmt.close();
}
if(conn!=null && !conn.isClosed()){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
3.2 BaseDAO抽取增删改通用方法
package com.atguigu.fruit.dao.base;
import java.sql.*;
public abstract class BaseDAO {
public final String DRIVER = "com.mysql.jdbc.Driver" ;
public final String URL = "jdbc:mysql://localhost:3306/fruitdb?useUnicode=true&characterEncoding=utf-8&useSSL=false";
public final String USER = "root";
public final String PWD = "123456" ;
protected Connection conn ;
protected PreparedStatement psmt ;
protected ResultSet rs ;
protected Connection getConn(){
try {
Class.forName(DRIVER);
return DriverManager.getConnection(URL, USER, PWD);
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
return null ;
}
protected void close(ResultSet rs , PreparedStatement psmt , Connection conn){
try {
if (rs != null) {
rs.close();
}
if(psmt!=null){
psmt.close();
}
if(conn!=null && !conn.isClosed()){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
protected int executeUpdate(String sql , Object... params){
try {
conn = getConn();
psmt = conn.prepareStatement(sql);
if(params!=null && params.length>0){
for (int i = 0; i < params.length; i++) {
psmt.setObject(i+1,params[i]);
}
}
return psmt.executeUpdate() ;
} catch (SQLException e) {
e.printStackTrace();
}finally {
close(rs,psmt,conn);
}
return 0;
}
}
3.3 抽取通用的查询方法-获取entityClass
T的Class对象 T: 参数化类型
如何获取entityClass对象? 如何确定有多少字段? ResultSetMetaData rsmd = rs.getMetaData(); //通过rs可以获取结果集的元数据 //元数据:描述结果集数据的数据 , 简单讲,就是这个结果集有哪些列,什么类型等等
private Class entityClass ;
public BaseDAO(){
Type genericType = getClass().getGenericSuperclass();
Type[] actualTypeArguments = ((ParameterizedType) genericType).getActualTypeArguments();
Type actualType = actualTypeArguments[0];
try {
entityClass = Class.forName(actualType.getTypeName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
通过反射技术给obj对象的property属性赋propertyValue值
private void setValue(Object obj , String property , Object propertyValue){
Class clazz = obj.getClass();
try {
Field field = clazz.getDeclaredField(property);
if(field!=null){
field.setAccessible(true);
field.set(obj,propertyValue);
}
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
1).数据源连接池
为什么需要数据源连接池? 准备10个connection对象,用的时候去取connection对象。
优点:
- 相应时间更快
- 连接对象的利用率更高
- 被close的连接对象并没有真正关闭,而是将状态重新设置为空闲状态,然后放回池子,这样下次获取连接对象,这个对象会被重复使用
- 没有close的连接对象会被一直占用,那么下次继续获取连接对象,是不会获取到这个对象的(hashcode没有重复,只出现一次)
读取外部的配置文件设置连接池
package com.atguigu.jdbc;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public class Demo04Druid {
public static void main(String[] args) throws SQLException, IOException {
Properties properties = new Properties();
InputStream is = Demo04Druid.class.getClassLoader().getResourceAsStream("jdbc.properties");
properties.load(is);
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(properties.getProperty("jdbc.driverClassName"));
dataSource.setUrl(properties.getProperty("jdbc.url"));
dataSource.setUsername(properties.getProperty("jdbc.username"));
dataSource.setPassword(properties.getProperty("jdbc.pwd"));
dataSource.setInitialSize(Integer.parseInt(properties.getProperty("jdbc.initSize")));
dataSource.setMaxActive(Integer.parseInt(properties.getProperty("jdbc.maxActive")));
dataSource.setMaxWait(Integer.parseInt(properties.getProperty("jdbc.maxWait")));
for(int i = 0 ; i<10 ; i++){
Connection conn1 = dataSource.getConnection();
System.out.println(i+"-------->"+conn1);
}
}
}
public class Demo05Druid {
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
InputStream is = Demo05Druid.class.getClassLoader().getResourceAsStream("jdbc2.properties");
properties.load(is);
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
for(int i = 0 ; i<10 ; i++){
Connection conn1 = dataSource.getConnection();
System.out.println(i+"-------->"+conn1);
}
}
}
2).JDBC的优化-难点
|