package study.jdbc;
import com.mysql.jdbc.Driver;
import java.sql.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* 1、导入驱动jar包
* 复制相应的jar包到项目中
* 将jar所在的目录添加为库(Iltellij IDE 选择jar所在目录右键添加为库)
*
* 2、注册驱动
* DriverManager:
* 驱动管理对象
* 功能:
* 1、注册驱动
* 2、获取数据库连接
* Connection:
* 数据库连接对象
* 功能:
* 1、获取执行sql的对象
* * Statement ceateStatement()
* * PreparedStatement prepareStatement(string sql)
* 2、管理事务
* * 开启事务:setAutoCommit(boolean autoCommit) 设置 false 开启事务
* * 提交事务:commit()
* * 回滚事务:rollback()
* Statement:
* 用于执行静态SQL语句并返回其生成的结果的对象
* 功能:
* 1、执行sql语句
* * execute(string sql) 执行任意的SQL语句
* * int executeUpdate(string sql) 执行 DML(insert、update、delete) 语句、DDL(create、alter、drop)语句 ,该方法返值是影响行数
* * ResultSet executeQuery(string sql) 执行 DQL(select)语句
* ResultSet:
* 结果集对象 表示数据库结果集的数据表,通常通过执行查询数据库的语句生成
*
*/
public class Jdbc {
public static void main(String[] args) {
/*
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//获取数据库连接对象
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root");
//定义sql语句
String sql = "select * from emp";
//获取SQL对象 Statement
Statement stmt = conn.createStatement();
//执行语句
ResultSet result = stmt.executeQuery(sql);
System.out.println(result);
//释放资源
stmt.close();*/
Connection conn = null;
Statement stmt = null;
ResultSet res = null;
//注册驱动
try {
Class.forName("com.mysql.jdbc.Driver");
//获取Connection连接对象
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test", "root", "root");
//获取执行SQL对象
stmt = conn.createStatement();
//定义SQL
//增
String insert = "insert into emp(id,ename,job_id,mgr,joindate,salary,bonus,dept_id) values(1,'乔峰',2,1010,'2001-09-28',29750,1000,20)";
//删
String delete = "delete from emp where id = 1";
//改
String update = "update emp set id = 2 where id = 1001";
//查
String select = "select * from emp";
//执行语句
/*int i1 = stmt.executeUpdate(insert);//影响行数
int i2 = stmt.executeUpdate(delete);//影响行数
int i3 = stmt.executeUpdate(update);//影响行数
System.out.println(i1);
System.out.println(i2);
System.out.println(i3);*/
//执行查询语句
//获取单个数据
res = stmt.executeQuery(select);
/*res.next();//指针向下移动一行 返回false表示已经到最后
System.out.println(res.getInt(1));
System.out.println(res.getString("ename"));
System.out.println(res.getInt("job_id"));*/
//遍历 将查询结果集封装为对象
Emp emp = null;
List<Emp> list = new ArrayList<>();
while (res.next()){
emp = new Emp();
emp.setId(res.getInt("id"));
emp.setEname(res.getString("ename"));
emp.setId(res.getInt("job_id"));
emp.setMgr(res.getInt("mgr"));
emp.setJoindate(res.getDate("joindate"));
emp.setSalary(res.getDouble("salary"));
emp.setBonus(res.getDouble("bonus"));
emp.setDept_id(res.getInt("dept_id"));
list.add(emp);
}
Iterator<Emp> it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (res != null) {
try {
res.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
}
Junit
例如我有一个类,需要测试程序是否OK
被测试对象:
package com.Junit;
/**
* 计算器类
* 定义了两个方法
*/
public class Calculator {
/**
* 加法
* @param a
* @param b
* @return
*/
public int add(int a,int b) {
return a + b;
}
/**
* 减法
* @param a
* @param b
* @return
*/
public int sub(int a,int b) {
return a - b;
}
}
测试JUnit类:
package com.test;
import com.Junit.Calculator;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class CalculatorTest {
/**
* @Before 注解:
* 测试方法中的初始化方法
*/
@Before
public void init(){
System.out.println("init");
}
/**
* @After 注解:
* 测试方法中的后置方法
*/
@After
public void close(){
System.out.println("close");
}
/**
* @Test 注解:
* 表示 该方法可以脱离main方法直接运行
* 测试add方法
*/
@Test
public void testAdd()
{
//System.out.println("执行了");
//创建测试对象
Calculator c = new Calculator();
int result = c.add(1, 2);
//对应测试结果,使用断言功能
//assertEquals() 第一个参数为期望值 第二个参数为结果值,程序将两个值进行比较
Assert.assertEquals(3,result);
System.out.println("测试完成");
}
}
测试输出结果:
TCP通信
package network;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
/**
* TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象,从而在通信的两端形成网络虚拟链路,一旦建立了虚拟的网络链路,两端的程序就可以通过该链路通信
*
* Java对于基于TCP协议的网络提供了良好的封装,使用Socket对象来代表两端的通信端口,并通过Socket产生IO流来进行网络通信
* Java为客户端提供了 Socket类 ,为服务端提供了ServerSocket类
*/
public class TcpDemo {
public static void main(String[] args) {
}
/**
* 服务端:
* 1、创建服务器端的Socket对象(ServerSocket)
* 2、获取输入流,读数据,并把数据显示在控制台
* 3、释放资源
*/
public static void server() throws IOException {
//创建服务器端的Socket对象(ServerSocket)
//ServerSocket(int port) 创建绑定到指定端口的服务器套接字
ServerSocket serverSocket = new ServerSocket(10086);
//accept() 侦听要连接到此套接字并接受它
Socket accept = serverSocket.accept();
//获取输入流
InputStream is = accept.getInputStream();
byte[] bys = new byte[1024];
int read = is.read(bys);
String s = new String(bys, 0, read);
System.out.println(s);
//回复客户端
OutputStream os = accept.getOutputStream();
os.write("收到了你的来信".getBytes(StandardCharsets.UTF_8));
}
/**
* 客户端:
* 1、创建客户端的Socket对象(Socket)
* 2、获取输出流,写数据
* 3、释放资源
*/
public static void client() throws IOException {
//创建客户端的Socket
//Socket(InetAddress address, int port) 创建流套接字并将其连接到指定IP地址的指定端口号。
Socket socket = new Socket("192.168.3.14",10086);
//获取输出流,写数据(发送到服务端)
OutputStream outputStream = socket.getOutputStream();
outputStream.write("你好,TCP".getBytes(StandardCharsets.UTF_8));
//读取服务端回复数据
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int read = inputStream.read(bytes);
String s = new String(bytes, 0, read);
System.out.println(s);
//关闭资源
socket.close();
}
}
UDP通信
package network;
import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;
/**
* UDP协议实现通信
* UDP协议是一种不可靠的网络协议,它在两端各建立一个Socketd对象,但是两个Socker只是发送数据和接收数据,
* 因此对于基于UDP协议的通信双方而言,没有所谓的客户端和服务端的概念
* Java提供了 DatagramSocket 类作为基于UDP协议的Socket实现功能
*/
public class UdpDemo {
public static void main(String[] args) {
}
/**
* UDP发送数据步骤:
* 1、创建发送端的Socket对象(DatagramSocket)
* 2、创建数据,并把数据打包
* 3、调用DatagramSocket对象的方法发送数据
* 4、关闭发送端
* @throws IOException
*/
public static void send() throws IOException {
//创建发送对象
DatagramSocket datagramSocket = new DatagramSocket();//"192.168.3.14"
//创建数据,并打包数据
//DatagramPacket(byte[] buf, int length, InetAddress address, int port) 构造一个数据包,发送长度为 length的数据包到指定主机上的指定端口号。
byte[] bytes = "你好455454".getBytes(StandardCharsets.UTF_8);//发送数据
InetAddress address = InetAddress.getByName("192.168.3.14");//发送IP
int port = 10086;//端口
DatagramPacket dp = new DatagramPacket(bytes, bytes.length,address,port);
//调用发送方法 send(DatagramPacket p)
datagramSocket.send(dp);
//关闭资源
datagramSocket.close();
}
/**
* UPD接收数据:
* 1、创建接收端的Socket对象(DatagramSocket)
* 2、创建一个数据包,用于接收数据
* 3、调用DatagramSocket对象方法接收数据
* 4、解析数据包、并把数据在控制台显示
* 5、关闭接收端
* @throws IOException
*/
public static void receive() throws IOException {
//创建接收对象
int port = 10086; //指定端口
DatagramSocket datagramSocket = new DatagramSocket(port);
//创建数据包,接收数据
byte[] bytes = new byte[1024];
//调用DatagramSocket对象方法接收数据
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
datagramSocket.receive(dp);
//解析数据
byte[] data = dp.getData();
int len = dp.getLength();
String s = new String(data,0,len);//将数据转换成String
System.out.println(s);
//关闭
//datagramSocket.close();
}
}
网络编程三要素
1、IP
- IP地址是网络中的合并的唯一表示,它分为两大类:
- IPv4
- IPv6
2、端口(port)
- 设备上应用程序的唯一标识符
- 端口号:用两个字节表示的整数,它的取值是0~65535,其中0~1023之间的端口用于一些知名的网络服务和应用
- 普通的应用程序需要使用1024以上的端口
3、协议
- 计算机网络中,连接和通信的规则被称为网络通信协议
- UDP协议:用户数据报协议(User Datagram Protocol)
- UPD协议是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接,简单来说,当一台计算机向另一台计算机发送数据时,发送端不会确认接收端舒服存在就会发送数据,同样,接收端不会反馈是否接收成功信息
- 由于使用UDP协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据传输
- ⬆:由于UDP面向的无连接性,不能保证数据的完整性,因此传输重要数据时不建议使用UDP协议
- TCP协议:(Transmission Control Protocol)
- TCP协议是面向连接的通信协议,即传输数据前需要在发送端和接收端建立逻辑连接,然后在传输数据,它提供了两台计算机之间可靠无差错的数据传输,在TCP连接中必须要明确客户端和服务端,由客户端向服务端发出连接请求,每次连接的创建都要经过“三次握手”
- 三次握手:
- 第一次握手,客户端向服务端发出连接请求,等待服务器确认
- 第二次握手,服务端向客户端回送一个响应,通知客户端收到了连接的请求
- 第三次握手,客户端再次向服务端发送确认信息,然后建立连接
- ⬆:重要数据传输建议用此协议
生产者和消费者
通过送奶工人(生产者)将牛奶放入奶箱(容器),提醒用户(消费者)取奶和开启等待和唤醒等待的业务行为演示生产者和消费者的逻辑关系,
运行入口:
package yield;
/**
* demo
*/
public class Demo {
public static void main(String[] args) {
//创建奶箱对象,这是共享数据区域
Box box = new Box();
//创建生产者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作
Producer producer = new Producer(box);
//创建消费者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用获取牛奶的操作
Customer customer = new Customer(box);
//创建线程对象,分别把生产者和消费者对象作为构造方法参数传递
Thread t1 = new Thread(producer);//生产者线程
Thread t2 = new Thread(customer);//消费者线程
//启动线程
t1.start();
t2.start();
}
}
奶箱(容器):
package yield;
/**
* 奶箱(容器)
*/
public class Box {
//奶瓶数量
private int milk;
//奶箱状态(默认情况下是没有牛奶的)
private boolean state = false;
/**
* 存储牛奶的动作
*
* @param milk 奶瓶
*/
public synchronized void put(int milk) {
//奶箱中还有牛奶(等待消费)
if (state){
//wait() 等待消费
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果没有牛奶,就放入牛奶(生产牛奶)
this.milk = milk;
System.out.println("送奶工将第 " + this.milk + " 放入奶箱");
//放入完毕,修改状态
this.state = true;
//放入后提醒消费者取奶(唤醒消费者)
this.notifyAll();
}
/**
* 拿出牛奶动作
*/
public synchronized void get() {
//奶箱中没有牛奶,等待放入牛奶(等待生产)
if (!state){
//等待生产
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果有牛奶,就拿出牛奶
System.out.println("用户拿到第 " + this.milk + " 瓶奶");
//拿出完毕后,修改状态
this.state = false;
//拿出牛奶后,提醒生产者继续放牛奶(唤醒生产者)
this.notifyAll();
}
}
送奶工人(生产者):
package yield;
/**
* 送奶工人(生产者)
*/
public class Producer implements Runnable {
private Box box;
public Producer(Box box) {
this.box = box;
}
@Override
public void run() {
for (int i = 1; i <= 5; i++){
this.box.put(i);//放入牛奶
}
}
}
用户(消费者):
package yield;
/**
* 牛奶订购者(消费者)
*/
public class Customer implements Runnable{
private Box box;
public Customer(Box box) {
this.box = box;
}
@Override
public void run() {
while (true){
box.get();//获取牛奶
}
}
}
线程安全
运行代码:
public static void main(String[] args) {
SellTicket st = new SellTicket();
Thread t1 = new Thread(st,"窗口1");
Thread t2 = new Thread(st,"窗口2");
Thread t3 = new Thread(st,"窗口3");
//启动线程
t1.start();
t2.start();
t3.start();
}
Demo1:
package course;
/**
* 买票窗口
*/
public class SellTicket implements Runnable {
private int tickets = 10;
@Override
public void run() {
int sum = 10;
while (true){
if (tickets > 0) {
tickets--;
System.out.println(Thread.currentThread().getName() + "正在出售第" + (sum - tickets) + "张票");
}
}
}
}
线程安全问题
运行以上代码,3个售票窗口售卖10张票会出现超卖或少卖的情况
为什么会出现问题?(这也是我们判断多线程程序是否会有数据安全问题的标准)
- 是否是多线程环境
- 是否有共享数据
- 是否有多条语句操作共享数据
如何解决多线程按问题?
- 让程序没有安全问题的环境
- 实现方式:把多条语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可
解决方法:
同步代码块:锁多条语句操作共享数据,可以使用同步代码块
格式:
synchronized(任意对象){多条语句操作共享数据的代码
}
- 通过Lock类
Demo2(修改Demo1,使用synchronized关键字):
package course;
/**
* 买票窗口
*/
public class SellTicket implements Runnable {
private int tickets = 10;
//使用同步代码块
private Object obj = new Object();
@Override
public void run() {
int sum = 10;
synchronized (obj) {
while (true) {
if (tickets > 0) {
tickets--;
System.out.println(Thread.currentThread().getName() + "正在出售第" +(sum - tickets)+ "张票");
}
}
}
}
}
Demo3(修改Demo2,使用Lock类):
package course;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 买票窗口
*/
public class SellTicket implements Runnable {
private int tickets = 10;
//使用Lock 通过Lock的实现类
private Lock lock = new ReentrantLock();
@Override
public void run() {
int sum = 10;
while (true) {
lock.lock();
if (tickets > 0) {
tickets--;
System.out.println(Thread.currentThread().getName() + "正在出售第" +(sum - tickets)+ "张票");
}
lock.unlock();
}
}
}
进销存/线程概述
进程:
- 进程是正在运行的程序
- 是系统进行资源分配和调用的独立单位
- 每一个进程都有它自己的内存空间和系统资源
线程:
- 是进程中的单个顺序控制流,是一条执行路径
- 单线程:一个程序如果只有一条执行路径,就是单线程程序
- 多线程:一个程序刚有多条执行路径,就是多线程程序
线程详细描述:以下摘自 知乎
- 线程在进程下行进(单纯的车厢无法运行)
- 一个进程可以包含多个线程(一辆火车可以有多个车厢)
- 不同进程间数据很难共享(一辆火车上的乘客很难换到另外一辆火车,比如站点换乘)
- 同一进程下不同线程间数据很易共享(A车厢换到B车厢很容易)
- 进程要比线程消耗更多的计算机资源(采用多列火车相比多个车厢更耗资源)
- 进程间不会相互影响,一个线程挂掉将导致整个进程挂掉(一列火车不会影响到另外一列火车,但是如果一列火车上中间的一节车厢着火了,将影响到所有车厢)
- 进程可以拓展到多机,进程最多适合多核(不同火车可以开在多个轨道上,同一火车的车厢不能在行进的不同的轨道上)
- 进程使用的内存地址可以上锁,即一个线程使用某些共享内存时,其他线程必须等它结束,才能使用这一块内存。(比如火车上的洗手间)-"互斥锁"
- 进程使用的内存地址可以限定使用量(比如火车上的餐厅,最多只允许多少人进入,如果满了需要在门口等,等有人出来了才能进去)-“信号量”
线程有两种调度模型:
- 分时调度模型:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间片
- 抢占式调度模型:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么随机选择一个,优先级高的线程或的CPU时间片相对多一些
NOTE:
- Java使用的是抢占式调度模型
- 假如计算机只有一个CPU,那么CPU在某一时刻只能执行一条指令,线程只有得到CPU时间片(也就是使用权),才可以执行指令
- 所以说线程程序的执行是 随机性 ,因为谁抢到CPU的使用权不一定
线程生命周期
Java特殊打印流
package io;
import java.io.*;
/**
* 特殊输入流:
* 1、标准输入流
* System.in:通常,该流对应于键盘输入或由主机环境或用户指定的另一个输入源
*/
public class Standard {
public static void main(String[] args) throws IOException{
// systemIn();
print();
}
/**
* 标准输入流:
* System.in
* 通常,该流对应于键盘输入或由主机环境或用户指定的另一个输入源
*/
public static void systemIn()throws IOException {
//标准输入流
InputStream is = System.in;
//字符流
InputStreamReader isr = new InputStreamReader(is);
//字符缓冲流
BufferedReader br = new BufferedReader(isr);
//读取输入内容
System.out.println(br.readLine());
//将读取的内容转换整型 注意:需要输入数字
//System.out.println(Integer.parseInt(br.readLine()));
}
/**
* 标准输出流:
* System.out
*/
public static void systemOut() {
//这个 没什么好说的
//System.out.println();
}
/**
* 字节打印流:
* PrintStream
* 该类打印到文件的内容: 输出即所得,输入什么就写入什么
*/
public static void print() throws IOException{
//字节打印流:操作文件
PrintStream ps = new PrintStream("P:\\demo\\ccccc.txt");
//打印内容
ps.print("---打印开始---");
//打印换行符
ps.println();
//打印 int
ps.print(100);
ps.println();
//打印 float
ps.print(100.99);
ps.println();
//打印 char
ps.print('a');
ps.println();
ps.print("---打印结束---");
}
}
Java字符流操作
package io;
import java.io.*;
/**
* 字符流操作
* InputStreamReader:是从字节流到字符流的桥梁
* 他读取字节,并使用指定的编码将其接吗为字符
* 使用的字符集可以由名称指定,也可以被明确指定,或者使用平台默认的字符集
*
* OutputStreamWrite:是从字符流到字节流的桥梁
* 使用指定的编码将写入的字符编码为字节
* 字符集可以由名称指定,也可以被明确指定,或者使用平台默认的字符集
*/
public class IODemo2 {
public static void main(String[] args) {
// writeBase();
// readBase();
// buffwritedBase();
buffreadBase();
}
/**
* 字符读取操作
*/
public static void readBase() {
try {
//字符读取操作 指定字符集
InputStreamReader isr = new InputStreamReader(new FileInputStream("P:\\demo\\aaaaa.txt"), "UTF-8");
//读取一个
int ch;
while ((ch = isr.read()) != -1) {
System.out.print((char) ch);
}
System.out.println("\r\n");
//读取多个
char[] chs = new char[1024];
int len;
while ((len = isr.read(chs)) != -1) {
System.out.print(new String(chs, 0, len));
}
isr.close();
} catch (IOException e) {
System.out.println(e);
}
}
/**
* OutputStreamWriter:
* 字符写入操作
* write : 写入数据(写入的数据暂存在缓冲区)
* flush : 刷新缓冲区(将缓冲区数据写入到文件)
* close : 关闭资源(关闭前刷新缓冲区)
*/
public static void writeBase() {
try {
//字符写入操作 指定字符集
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("P:\\demo\\aaaaa.txt"), "UTF-8");
osw.write("我喜欢编程");//直接写入字符
osw.write("\r\n");//直接写入字符
osw.write("我喜欢Java");//直接写入字符
// osw.close();
osw.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 字符缓冲流 写入数据
* newLine:根据当前平台写入自适应的换行符号
*/
public static void buffwritedBase(){
try{
BufferedWriter bw = new BufferedWriter(new FileWriter("P:\\demo\\bbbbbb.txt"));
//写入数据
for (int i = 0; i < 10; i++){
bw.write("Hello"+i);
bw.newLine();//自适应平台的换行符,该方法是字符缓冲流类(BufferedWriter)的特有方法
bw.flush();
}
bw.close();
}catch (IOException e){
System.out.println(e);
}
}
/**
* 字符缓冲流 读取数据
* readLine:每次读取一行内容(不包括换行符),返回 null 表示结束
*/
public static void buffreadBase() {
try{
BufferedReader br = new BufferedReader(new FileReader("P:\\demo\\bbbbbb.txt"));
//读取数据
String str;
while ((str = br.readLine()) != null){
System.out.println(str);
}
br.close();
}catch(IOException e){
}
}
}