外键:
现在我们有两张表”分类表“和”商品表“,为了表明商品属于哪个分类,通常情况下,我们将在商品表上加一列,用于存放 cid 的信息,此列称为:外键
category(分类) |
cid |
cname |
products(商品) |
pid |
name |
price |
category_id(外键字段) |
此时”分类表 category“称为主表,”cid“我们称之为主键,”商品表 products“称为从表,”category_id“称为外键,我们通过主表的主键和从表的外键来描述主外键关系,呈现出的是一对多的关系。
外键特点:
从表外键值是 对主表主键的引用
从表外键类型必须和主表主键类型一致
声明外键约束:
语法:alter table 从表 add [constraint] [外键名称] foreign key(从表外键字段名) refereces
主表 (主表的主键)
创建分类表:
CREATE TABLE category(
cid VARCHAR(32) PRIMARY KEY,
cname VARCHAR(100)
);
INSERT INTO category(cid,cname) VALUES('c001','家电');
INSERT INTO category(cid,cname) VALUES('c002','服饰');
INSERT INTO category(cid,cname) VALUES('c003','化妆品');
创建商品表:
CREATE TABLE category(
cid VARCHAR(32) PRIMARY KEY,
cname VARCHAR(100)
);
INSERT INTO product(pid,pname,price,category_id) VALUES('p001','联想','5000','c001');
INSERT INTO product(pid,pname,price,category_id) VALUES('p002','海尔','5000','c001');
INSERT INTO product(pid,pname,price,category_id) VALUES('p003','雷神','5000','c001');
INSERT INTO product(pid,pname,price,category_id) VALUES('p004','JACK JONES','800','c002');
INSERT INTO product(pid,pname,price,category_id) VALUES('p005','真维斯','200','c002');
INSERT INTO product(pid,pname,price,category_id) VALUES('p006','花花公子','440','c002');
INSERT INTO product(pid,pname,price,category_id) VALUES('p007','劲霸','2000','c002');
INSERT INTO product(pid,pname,price,category_id) VALUES('p008','香奈儿','800','c003');
INSERT INTO product(pid,pname,price,category_id) VALUES('p009','相宜本草','200','c003');
建立关联:
alter table product add foreign key (category_id) references category(cid)
使用外键的目的:
保证数据的完整性
一对多建表原则:
在多的一方创建一个字段,字段作为外键指向一的一方的主键
多对多关系建表原则:
需要创建第三张表,中间表至少l两个字段,这两个字段分别作为外键指向另一方主键。
创建订单表:
CREATE TABLE orders(
oid VARCHAR(32) PRIMARY KEY,
totalprice DOUBLE
);
创建订单项表:
CREATE TABLE orderitem(
oid VARCHAR(50),
pid VARCHAR(50)
);
订单表和订单项表的主外键关系:
alter table orderitem add constraint orderitem_orders_fk foreign key(oid) references orders(oid);
商品表和订单项表的主外键关系:
alter table orderitem add constraint orderitem_product_fk foreign key(pid) references product(pid);
多表查询(三种方式及其区别)
1、交叉连接查询:
SELECT * FROM category,product;
1 queries executed, 1 success, 0 errors, 0 warnings
查询:select * from category,product LIMIT 0, 1000
返回了 27 行
执行耗时 : 0.042 sec
传送时间 : 0.001 sec
总耗时 : 0.044 sec
2、内连接查询(使用关键字 inner join --inner可以省略):
隐式内连接:select * from A,B where 条件;
显示内连接:select * from A inner join B on 条件;
3、外连接查询:(使用关键字 outer join --outer可以省略)
左外连接:left outer join
select * from A left outer join B on 条件
右外连接:right outer join
select * from A right outer join B on 条件
现在看看左外连和右外连接的区别:
INSERT INTO category VALUES('c004',NULL);
INSERT INTO product VALUES ('p010','海飞丝',0.5,NULL);
子查询:
一条 select 语句结果作为另一条 select 语法的一部分(查询条件, 查询结果, 表等)。
查询“化妆品”分类上架商品信息
JDBC工具类:
package com.itcast.ma;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 工具类
* 提供获取连接及释放资源的方法
* @author lenovo
*
*/
public class JDBCUtils {
/**
* 获取连接方法
* @return
*/
public static Connection getConnection(){
Connection conn = null;
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
/**
* 释放资源方法
* @param conn
* @param pstmt
* @param rs
*/
public static void release(Connection conn, PreparedStatement pstmt, ResultSet rs){
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(pstmt != null){
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
查询数据:
package
com.ma.test;
import
java.sql.Connection;
import
java.sql.PreparedStatement;
import
java.sql.ResultSet;
import
java.sql.SQLException;
import
org.junit.Test;
import
com.itcast.ma.JDBCUtils;
/**
*测试工具类
*
@author
lenovo
*
*/
public
class
TestUtils {
/**
* 根据id查询
*/
@Test
public
void
testFindUserById
(){
Connection conn =
null
;
PreparedStatement pstmt =
null
;
ResultSet rs =
null
;
try
{
//1、获取连接
conn = JDBCUtils.
getConnection
();
//2、编写
sql
String sql =
"select * from t_user where uid = ?"
;
//3、获取执行语句对象
pstmt = conn.prepareStatement(sql);
//4、设置参数
pstmt.setInt(1, 2);
//5、查询
rs = pstmt.executeQuery();
//6、处理资源
while
(rs.next()){
System.
out
.println(rs.getString(2)+
"----"
+ rs.getString(
"password"
));
}
}
catch
(SQLException e) {
e.printStackTrace();
}
finally
{
//7、释放资源
JDBCUtils.
release
(conn, pstmt, rs);
}
}
}
测试结果:
使用 properties 配置文件:
开发过程中获得连接的四个参数(驱动、url 、用户名、密码)通常都存放在配置文件中,方便后期维护,程序如果需要更换数据库,只需要修改配置文件即可。
1、文件位置:建议 src 下面。
2、文件名称:任意,扩展名为 properties。
3、文件内容:一行一组数据,格式是“key = value”;key 名自定义,如果多个单词用 . 分隔;value 不支持中文。
driver = com.mysql.jdbc.Driver
url = jdbc;mysql://localhost:3306/user?useUnicode = true & characterEncoding = utf-8
username = rooot
password = 123456
加载配置文件:ResourceBundle 对象。
package
com.itcast.ma;
import
java.util.ResourceBundle;
/**
* 工具类
* 提供获取连接及释放资源的方法
*
@author
lenovo
*
*/
public
class
JDBCUtils {
private
static
String
driver
;
//驱动
private
static
String
url
;
//路径
private
static
String
user
;
//用户
private
static
String
password
;
//密码
/**
* 配置文件只需要加载一次,提供静代码,当前类被加载到内存执行
*/
static
{
//1、使用 JDK 提供的工具类加载 properties 文件
//ResourceBundle 专门处理 properties 文件,提供 getBundle() 方法,只需要写入文件。
ResourceBundle bundle = ResourceBundle.
getBundle
(
"db"
);
//2、通过 key 获取需要的值
driver
= bundle.getString(
"driver"
);
url
= bundle.getString(
"url"
);
user
= bundle.getString(
"username"
);
password
= bundle.getString(
"password"
);
}
}
插入数据:
/**
* 添加用户信息方法
*/
@Test
public
void
testAdd
(){
Connection conn =
null
;
PreparedStatement pstmt =
null
;
try
{
//1、获取连接
conn = JDBCUtils.
getConnection
();
//2、书写
sql
语句
String sql =
"insert into t_user values(null,?,?,?)"
;
//3、获取
sql
执行对象
pstmt = conn.prepareStatement(sql);
//4、设置参数
pstmt.setString(1,
"MaYue"
);
pstmt.setString(2,
"321456"
);
pstmt.setString(3,
"LIN"
);
//5、执行插入操作
int
row = pstmt.executeUpdate();
if
(row > 0){
System.
out
.println(
"插入成功 !"
);
}
}
catch
(SQLException e) {
e.printStackTrace();
}
}
删除数据:
/**
* 根据id 删除用户的方法
*/
@Test
public
void
testDelete
(){
Connection conn =
null
;
PreparedStatement pstmt =
null
;
try
{
//1、获取连接
conn = JDBCUtils.
getConnection
();
//2、书写
sql
语句
String sql =
"delete from t_user where uid = ?"
;
//3、获取
sql
执行对象
pstmt = conn.prepareStatement(sql);
//4、设置参数
pstmt.setInt(1, 9);
//5、执行插入操作
int
row = pstmt.executeUpdate();
if
(row > 0){
System.
out
.println(
"删除成功 !"
);
}
else
{
System.
out
.println(
"删除失败 !"
);
}
}
catch
(SQLException e) {
e.printStackTrace();
}
finally
{
//6、释放资源
JDBCUtils.
release
(conn, pstmt,
null
);
}
}
更新数据:
/**
* 根据id 更新用户的方法
*/
@Test
public
void
testUpdate
(){
Connection conn =
null
;
PreparedStatement pstmt =
null
;
try
{
//1、获取连接
conn = JDBCUtils.
getConnection
();
//2、书写
sql
语句
String sql =
"update t_user set password = ? where uid = ?"
;
//3、获取
sql
执行对象
pstmt = conn.prepareStatement(sql);
//4、设置参数
pstmt.setString(1,
"666666"
);
pstmt.setInt(2, 1 );
//5、执行插入操作
int
row = pstmt.executeUpdate();
if
(row > 0){
System.
out
.println(
"更新成功 !"
);
}
else
{
System.
out
.println(
"更新失败 !"
);
}
}
catch
(SQLException e) {
e.printStackTrace();
}
finally
{
//6、释放资源
JDBCUtils.
release
(conn, pstmt,
null
);
}
}