第十四天三月份8日之多表设计和JDBC、静态工厂设计模式

第十四天3月8日之多表设计和JDBC、静态工厂设计模式


一、SQL中多表设计
1、一对多
create table DEPARTMENT(
 ID int primary key,
 NAME varchar(100) not null
);

create table EMPLOYEE(
 ID int primary key,
 NAME varchar(100) not null,
 SALARY float(8,2),
 DEPART_ID int,
 constraint DEPART_ID_FK foreign key (DEPART_ID) references DEPARTMENT(ID)
);
2、多对多
create table TEACHER(
 ID int primary key,
 NAME varchar(100) not null,
 SALARY float(8,2)
);
create  table STUDENT(
 ID int primary key,
 NAME varchar(100) not null,
 GRADE varchar(100)
);
create table TEACHER_STUDENT(
 T_ID int,
 S_ID int,
 primary key(T_ID,S_ID),
 constraint T_ID_FK foreign key (T_ID) references TEACHER(ID),
 constraint S_ID_FK foreign key (S_ID) references STUDENT(ID)
);
3、一对一
a、按照外键关联(用一对多模拟的)
create table PERSON1(
 ID int primary key,
 NAME varchar(100),
 GENDER varchar(100)
);
create table ID_CARD1(
 ID int primary key,
 NUMBER varchar(100),
 PERSON_ID int unique,
 constraint PERSON_ID_FK foreign key (PERSON_ID) references PERSON1(ID)
);
b、按照主键关联
create table PERSON2(
 ID int primary key,
 NAME varchar(100),
 GENDER varchar(100)
);
create table ID_CARD2(
 ID int primary key,
 NUMBER varchar(100),
 constraint PERSON_ID_FK1 foreign key (ID) references PERSON2(ID)
);
二、多表查询

+----+----------+------+
| id | name     | city |
+----+----------+------+
|  1 | 陈冠希   | 香港     |
|  2 | 李宗瑞         | 台北    |
|  3 | 苍井空        | 东京     |
|  4 | 钟欣桐        | 香港     |
|  5 | 芙蓉姐姐       | NULL |
+----+----------+------+

+----+--------------+---------+-------------+
| id | order_number | price   | customer_id |
+----+--------------+---------+-------------+
|  1 | 0001         |  100.00 |           1 |
|  2 | 0002         |  200.00 |           1 |
|  3 | 0003         |  300.00 |           1 |
|  4 | 0004         |  100.00 |           2 |
|  5 | 0005         |  200.00 |           3 |
|  6 | 0006         |  100.00 |           4 |
|  7 | 0007         | 1000.00 |        NULL |
+----+--------------+---------+-------------+


1、连接查询(面试必面)
 
 基本语法:from LEFTTABLE 连接类型(cross join|inner join|left [outer] join|right [outer] join|UNION) RIGHTTABLE [on 连接条件] [where 过滤条件]

 1.1交叉连接查询(cross join)
  结果:返回两张表的笛卡尔积。(5*7=35)
  select * from CUSTOMER cross join ORDERS;
 1.2内连接查询
  隐式内连接:不适用连接类型和on关键字。连接条件用where来连接
   有订单的客户和订单信息:select c.name,c.city,o.order_number,o.price from CUSTOMER c,ORDERS o where c.id=o.customer_id;
  显式内连接:(inner join)
   有订单的客户和订单信息:select c.name,c.city,o.order_number,o.price from CUSTOMER c inner join ORDERS o on c.id=o.customer_id;
 1.3外连接查询
  左外连接:(left [outer] join).
   返回满足连接条件的记录,同时返回左表中剩余的所有记录。
   显示所有的客户信息,有订单的还要显示对应的订单信息。
   select c.name,c.city,o.order_number,o.price from CUSTOMER c left join ORDERS o on c.id=o.customer_id;
  右外连接:(right [outer] join)
   返回满足连接条件的记录,同时返回右表中剩余的所有记录。
   显示所有的订单信息,有客户的还要显示对应的客户信息。
   select c.name,c.city,o.order_number,o.price from CUSTOMER c right join ORDERS o on c.id=o.customer_id;
2、联合查询:(UNION)
 返回多条语句查询的记录的并集,去除重复的记录。
 查询订单金额在200以上,且客户的id为1的记录
 select * from ORDERS where price>200 UNION select * from ORDERS where customer_id=1;

3、子查询:(嵌套查询)
 查询“陈冠希”的所有订单信息
 select * from ORDERS where CUSTOMER_ID=(select ID from CUSTOMER where NAME='陈冠希');
4、报表查询:(使用数据库提供的函数)

统计一个班级共有多少学生?
mysql>select count(ID) from STUDENT;
select count(*) from STUDENT;
统计数学成绩大于90的学生有多少个?
mysql>select count(math) from STUDENT where math>=90;
统计总分大于250的人数有多少?
mysql>select count(*) from STUDENT where chinese+math+english>250;

统计一个班级数学总成绩?
mysql>select sum(MATH) from STUDENT;
统计一个班级语文、英语、数学各科的总成绩
mysql>select sum(chinese),sum(english),sum(math) from STUDENT;
统计一个班级语文、英语、数学的成绩总和
mysql>select sum(chinese+english+math) from STUDENT;
统计一个班级语文成绩平均分
mysql>select sum(chinese)/count(ID) from STUDENT;

求一个班级数学平均分?
mysql>select avg(MATH) from STUDENT;
求一个班级总分平均分
msyql>select avg(chinese+english+math) from STUDENT;

对订单表中商品归类后,显示每一类商品的总价
msyql>select sum(PRICE),PRODUCT from ORDERS group by PRODUCT
查询购买了几类商品,并且每类总价大于100的商品
msyql>select sum(PRICE),PRODUCT from ORDERS group by PRODUCT having sum(PRICE)>100;

随机取3条记录
select * from orders order by rand() limit 0,3;


三、数据库的备份与恢复

1、备份
c:\>mysqldump [-h localhost] -u root -p test>d:/test.sql

2、恢复

前提:数据库名必须存在
方式一:
c:\>mysql -u root -p test<d:/test.sql
方式二:
mysql>use test;
mysql>source d:/test.sql;


四、JDBC概述(JavaEE技术之一,规范:接口和抽象类组成)
Java Data Base Connectivity 用Java语言连接数据库操作
1、API:在JDK中。
 java.sql.*;
 javax.sql.*;
2、JDBC和数据库驱动的关系:抽象和实现的关系

3、第一个JDBC程序:查询USES表中的所有记录,打印到控制台上
a、把数据库的驱动加入到构建路径中
b、编写步骤:(非常重要)
 1、注册驱动
 2、获取与数据库的连接(所有的操作都是建立在连接之上)
 3、得到代表sql语句的对象
 4、执行语句
 5、如果执行的是查询语句,遍历结果集
 6、释放占用的资源
五、JDBC常用的接口
1、DriverManager:注册驱动和获取与数据库的连接
 a、注册驱动:
  方式一(不建议使用):DriverManager.registerDriver(new com.mysql.jdbc.Driver());
    缺点:1、依赖具体的数据库驱动;2、会导致驱动注册2遍。
  方式二(推荐):Class.forName("com.mysql.jdbc.Driver")
 b、获取与数据库的连接:
  Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day14", "root", "sorry");
  
  url:数据库厂商与SUN定义的连接协议
   jdbc:数据库厂商:[子协议]:主机:端口
   常见的数据库连接URL(建议查看数据库对应的文档)
   MySQL:  jdbc:mysql://localhost:3306/day14 == jdbc:mysql:///day14  (默认本机的3306端口)
   Oracle: jdbc:oracle:thin:@localhost:1521:orcl
   

   
  获取连接的重载方法:
   DriverManager.getConnection(String url, String username, String  password);
   DriverManager.getConnection(String url, Properties info)
   DriverManager.getConnection(String url):   url?p1=value1&p2=value2
   
2、Connection:代表与数据库的连接。所有的与数据库的交互都是基于该对象
 Statement stmt = conn.createStatement();
3、Statement:代表SQL语句对象
 ResultSet executeQuery(String dqlSql)
 int executeUpdate(String dmlSQL)
 boolean execute(String sql):返回值不代表成功与否。有没有结果集。有true
 
4、ResultSet:代表查询的结果集
 提供了一些获取字段值的重载方法:可以按照索引取(从1开始),亦可以按照字段名来取
 boolean next():游标往下移动一个
 boolean previous():游标往上移动一个
 void absolute(int index):绝对定位
 void beforeFirst():移动游标第一行的前面
 void afterLast():移动游标到最后一行的后面
 
5、PreparedStatement:接口 (能用该接口就不用Statement)
 a、防止SQL注入
 b、预编译SQL语句,执行效率比Statment高
 c、参数可以使用占位符(?)

 

driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/MYDB1
username=root
password=sorry

package com.itheima.util;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class JdbcUtil {
	private static String driverClass;
	private static String url;
	private static String username;
	private static String password;
	static {
		try {
			InputStream in = JdbcUtil.class.getClassLoader()
					.getResourceAsStream("dbcfg.properties");
			Properties pro = new Properties();

			pro.load(in);
			driverClass = pro.getProperty("driverClass");
			url = pro.getProperty("url");
			username = pro.getProperty("username");
			password = pro.getProperty("password");
			Class.forName(driverClass);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static Connection getConnection() throws Exception {
		return DriverManager.getConnection(url, username, password);
	}

	public static void release(ResultSet rs, Statement stmt, Connection conn) {
		if (rs != null) {
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if (stmt != null) {
			try {
				stmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if (conn != null) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}


package com.itheima.jdbc;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

import org.junit.Test;

import com.itheima.util.JdbcUtil;

public class JdbcDemo {

	@Test
	public void add() {
		Connection conn = null;
		Statement state = null;
		try {
			conn = JdbcUtil.getConnection();
			state = conn.createStatement();
			int i = state
					.executeUpdate("insert into user2 values(null,'王二','123','12312@qq.com','1990-09-09')");
			if (i > 0)
				System.out.println("插入成功!");
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			JdbcUtil.release(null, state, conn);
		}

	}
	@Test
	public void delete() {
		Connection conn = null;
		Statement state = null;
		try {
			conn = JdbcUtil.getConnection();
			state = conn.createStatement();
			int i = state
					.executeUpdate("delete from user2 where id=2");
			if (i > 0)
				System.out.println("删除成功!");
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			JdbcUtil.release(null, state, conn);
		}
		
	}
	@Test
	public void update() {
		Connection conn = null;
		Statement state = null;
		try {
			conn = JdbcUtil.getConnection();
			state = conn.createStatement();
			int i = state
					.executeUpdate("update user2 set password='123456' where id = 1");
			if (i > 0)
				System.out.println("更新成功!");
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			JdbcUtil.release(null, state, conn);
		}
		
	}
	@Test
	public void query() {
		Connection conn = null;
		Statement state = null;
		try {
			conn = JdbcUtil.getConnection();
			state = conn.createStatement();
			ResultSet re = state	.executeQuery("select * from user2");
			while(re.next()){
				System.out.println(re.getString("name"));
				System.out.println(re.getString("password"));
				System.out.println(re.getString("email"));
				System.out.println(re.getDate("birthday"));
				System.out.println("--------------------------------------------");
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			JdbcUtil.release(null, state, conn);
		}
		
	}
}



 静态工厂:

package com.itheima.dao;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import com.itheima.exception.DaoException;

public class DaoFactory {
	
	private static String userDaoImplClassName;
	static{
		try {
			InputStream in = DaoFactory.class.getClassLoader().getResourceAsStream("dao.properties");
			Properties props = new Properties();
			props.load(in);
			userDaoImplClassName = props.getProperty("userDao");
		} catch (IOException e) {
			throw new ExceptionInInitializerError(e);
		}
	}
	
	public static UserDao getUserDaoInstance(){//静态工厂
		try {
			return (UserDao) Class.forName(userDaoImplClassName).newInstance();//通过反射拿到UserDaoMySqlImpl类的实例
		} catch (Exception e) {
			throw new DaoException("Instance UserDao failure,please check you dao config files");
		}
	}
}

package com.itheima.service.impl;

import com.itheima.dao.DaoFactory;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.exception.UserExistException;
import com.itheima.service.BusinessService;

public class BusinessServiceImpl implements BusinessService {
	private UserDao dao = DaoFactory.getUserDaoInstance();//不直接依赖哪一个具体的实现,要什么实例,直接问工厂要。
																							//这是工厂设计模式
	public void regist(User user) throws UserExistException {
		//检查用户名是否存在
		boolean b = checkUsernameIsExist(user.getUsername());
		if(b)
			throw new UserExistException("The username "+user.getUsername()+" exist,please change another");
		dao.addUser(user);
	}

	public boolean checkUsernameIsExist(String username) {
		return dao.findUserByUsername(username);
	}

	public User login(String username, String password) {
		return dao.findUser(username, password);
	}

}