Day29-JDBC
*理解:IDBC可以理解为JAVA后台的代码对数据库中的数据进行操作。常用的就是CRUD的增删改查方法。通过不同的SQL语句来实现不同的功能。*
*2:JDBC的步骤*
口诀:贾琏欲执事
/**
* 贾琏欲执事
*/
//第一步:贾,加载驱动
Class.forName("com.mysql.jdbc.Driver");
/**
* 第二部:琏,获取连接对象
* Connection 是一个接口,采取了多台的方式获取对象
*/
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mbs", "root", "123456");
/**
* 第三步:欲,获取语句对象 即操作数据库的SQL语句
*/
String sql = "select * from mbs.student";
StringBuffer sql1 = new StringBuffer();
sql1.append("CREATE TABLE `mbs`.`person`( ");
sql1.append("`id` SMALLINT(2) NOT NULL AUTO_INCREMENT,");
sql1.append("`name` CHAR(20) NOT NULL,");
sql1.append("`age` INT(2) NOT NULL,");
sql1.append("PRIMARY KEY (`id`)");
sql1.append(" );");
String addsql = "INSERT INTO person (name,age) VALUES ('苍苍',18)";
String updatsql = "Update student set name='麻园' where id = 1 ";
System.out.println(sql1.toString());
Statement statement = connection.createStatement();
/**
* 第四步,执,执行语句获取一个结果集合
*/
//boolean execute = statement.execute(sql1.toString());
//查看见表是否成功
//System.out.println(execute);
//boolean execute = statement.execute(addsql);
//System.out.println("是否已经添加数据成功"+execute);
boolean execute = statement.execute(updatsql);
System.out.println("是否已经修改数据成功:"+execute);
ResultSet set = statement.executeQuery(sql);
System.out.println("id\t name\t age");
while (set.next()) {
System.out.print(set.getInt("id")+"\t");
System.out.print(set.getString("name")+"\t");
System.out.println(set.getInt("age"));
}
/**
* 第五步,释,释放资源
*/
statement.close();
connection.close();
*3:三层架构*
*Dao层*
*接口类,专门写实现自己目的的抽象方法,用XxxImpl实现类去对抽象方法进行重写实现该抽象方法。*
public interface IStudentDao {
/**
* 增添数据
* @param stu
*/
void add(Student stu);
}
实现类:重写实现Dao层方法
/**
* 增加数据的实现方法
* @param stu
*/
@Override
public void add(Student stu) {
Connection con = null;
Statement pstmt = null;
try {
// 贾: 加载驱动
Class.forName("com.mysql.jdbc.Driver");
// 链:获取数据库链接对象
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/mbs", "root", "123456");
// 执:增加执行语句
String sql = "INSERT INTO `mbs`.`student` (`id`, `name`, `age`, `password`) VALUES (DEFAULT , '"+stu.getName()+"', '"+stu.getAge()+"', '"+stu.getPassword()+"')";
System.out.println(sql);
pstmt = con.createStatement();
pstmt.execute(sql);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
// 事:释放资源即关流
try {
if (pstmt != null)
pstmt.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
if (con != null)
con.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("-----增加成功------");
}
*不论是增添数据还是修改数据,所有的代码都有一个共同
的点:加载对象,获取连接,释放资源,所有的代码都是一样的,有相同的代码,我们可以抽取出来作为一个类中保存,这个类就是工具人util类*
public class JdbcUtil {
/**
* 静态代码块,只要运行了jdbcUtil对象,就自动加载这个代码加载驱动
*/
static{
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 获取链接
* @return
*/
public static Connection getConnerction(){
try {
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mbs", "root", "123456");
return conn;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
/**
* 释放资源
*/
public static void closeResource(Connection conn, Statement statement, ResultSet rs){
try {
if (rs != null)
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (statement != null)
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
*Util层
*把重复代码写成一个工具类后,实现类的方法代码就简化了许多,直接调用JdbcUitl.方法名来调用,简化后的代码如图,很直观的简化了大量重复代码。*
public void delete(Integer id) {
Connection con = null;
Statement statement = null;
try {
con = JdbcUtil.getConnerction();
// 执:增加执行语句
String sql = " DELETE FROM student WHERE id = " + id;
statement = con.createStatement();
statement.execute(sql);
} catch (SQLException e) {
e.printStackTrace();
}
// 事:释放资源即关流
JdbcUtil.closeResource(con,statement,null);
System.out.println("-----删除成功------");
}
*properties读取文件*
*在之前的**getConnection***(***url,username,password***)****中,我们把所有的路径都写死了,为了方便我们使用,可以单独提取一个文件,专门写连接数据库的四大金刚,创建一个resources文件夹,写进一个db.properties文件,将JDBC四大金刚写进去**
driver=com.mysql.jdbc.Driver //固定不动
url=jdbc:mysql:///mbs //连接自己的数据库 mbs为数据库名
username=root //本地连接的用户名
password=123456 //密码
创建完文件后,我们要去需要用到这几个属性的地方进行修改,有两种方式,第一种是用读取文件方式获得里面的内容,然后对四个金刚进行赋值,这个方法比较复杂且步骤多
static {
File file = new File("config/database.properties");
InputStream is = null;
try {
is = new FileInputStream(file);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
// Properties类,专门用户读取和写入Properties文件的类
Properties properties = new Properties();
try {
System.out.println(is);
properties.load(is);
} catch (IOException e) {
e.printStackTrace();
}
driver = properties.getProperty("driver");
url = properties.getProperty("url");
user = properties.getProperty("user");
password = properties.getProperty("password");
第二个方法,直接读取,本质上和上面的差不多,但是简洁点
static Properties p = new Properties();
static{
try {
//读取properties文件
p.load( Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties") );
Class.forName(p.getProperty("driverClass"));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取链接
* @return
*/
public static Connection getConnerction(){
try {
//用一串地址表示,以后我们需要改表名什么的,直接在properties文件里修改数据即可,方便快捷
Connection conn = DriverManager.getConnection(p.getProperty("url"), p.getProperty("username"),p.getProperty("password"));
return conn;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
*用properties文件写四大金刚的***好处****:类似于抽取工具类,只要在工具类即properties中修改了数据,整体数据也会随之改变,譬如以后数据库名字被改动,不需要去检查各个代码的url地址有没有问题。高效快捷。**
Day30-JDBC深入
深入了解面向对象思想:万物皆对象,在JAVA语言中,所有的东西都可以看成一个对象来处理,所有的语言设计都是基于现实联系的,是通过计算机将联系体现出来。
java数据类型 – 对象的【值】也就是对象的数据类型 类似于人在父母眼里是孩子,在老师眼里是学生,标签属性。
类与对象–就是数据类型
1.PreparedStatemend
PreparedStatemend 是Statemend的一个子类,现在基本可以取缔在JDBC中Statemend中的地位,主要是使用起来会比较方便,我们写代码的时候在SQL语句中不需要硬性拼写,缺的对象可以用?来代替,然后用ps.serObject()方法去给?赋值,清晰明了且安全。
Statement:拼接SQL语句麻烦,由于它是静态的SQL语句,只有执行的时候才会传入数据库,验证语法编译,效率挺低的。
PreparedStatemend :ps = conn.prepareStatement(sql) 即在创建对象的时候就已经将SQL传入数据库,只需等待我们赋值就运行。
String sql = "INSERT INTO `student` (`id`, `name`, `age`, `password`) VALUES (DEFAULT,?,?,?)";
//PreparedStatement prepareStatement(String sql)
ps = conn.prepareStatement(sql);
//对SQL语句的?对象赋值,根据对象的数据类型改动
ps.setString(1,"波多");
ps.setInt(2,18);
ps.setString(3,"boduoyejieyi");
ps.execute();
2.完成登录功能
登录其实就是连接数据的账号/帐号密码,当账号和密码对应的话,登录成功。个人理解就是平常我们在网页登录帐号的时候,有帐号密码,我们将输入的帐号密码作为参数传入后台,后台根据方法去数据库中找匹配的,如果说找到了,我们就登录成功,如果说我们将帐号密码输入错误,数据库中没有能对应我们的数据,就会提示登录失败,即寻找不到数据。
//方便释放资源
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
//加载驱动,获取连接
conn = JdbcUtil.getConnerction();
//定义sql语句
String sql = "select * from student where name = ? and password = ?";
ps = conn.prepareStatement(sql);
//给SQL语句中的?赋值
ps.setString(1,username);
ps.setString(2,password);
//获取执行SQL后的数据
rs = ps.executeQuery();
//这里就是如果说rs有值,就说明username和password可以查到,即登录成功
if (rs != null){
System.out.println("登陆成功");
while (rs.next()){
return new Student(rs.getInt("id"),rs.getString("name"),rs.getInt("age"),rs.getString("password"));
}
}else {
System.out.println("登陆失败");
}
}catch (Exception e){
e.printStackTrace();
}finally {
JdbcUtil.closeResource(conn,ps,rs);
}
return null;
3.sql注入问题
sql注入问题其实就是在我们用Statement(sql);的时候,我们给SQL里面的字符串赋值时,字符串里面如果带有SQL语句的关键词,也能会改变SQL语句的意思,简单测试:
/**
* 测试SQL注入问题
* @throws Exception
*/
@Test
public void testlogin1() throws Exception{
String username = " ' or 1=1 or ' ";
si.login(username);
}
很明显,我们输入的username在数据库中是不存在的,但是却还是可以登录,为什么? 原因是:
sql = "select * from student where name = ’ or 1=1 or ';
后面的or 1 = 1是一个永恒成立的条件,所以无论你用什么username登录都会成立。这也就是不推荐使用Statement的原因。
使用PreparedStatemend ,它达构的语句是一个模板,我们不能更改,即不会拼接字符串,也就没有SQL注入的问题。
4.事务
事务:硬性理解为一个串在一起的几件事。简单举例就是微信转账,要么双方都成功,要么双方都失败。不能出现一方转账失败但是另一方收账成功的局面。在数据库中,事务的理解就是串在一起的一组操作单元,所以有开始也有结束,中间任何一个环节出现问题,就必须回滚,即退回到操作之前的状态。
事务的四大属性:
1.原子性:即执行的这一组操作单元全成功,才算事务成功。
2.一致性:指的是数据组的操作不能打破数据中数据的完整性和业务逻辑上的一致性。譬如只有10块钱不能转11块钱的帐
3.隔离性:指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间
4.持久性:事务一旦结束,就是永久保存的状态。转出去的钱,不可能平白能给你退回。
conn = JdbcUtil.getConnection();
st = conn.createStatement();
//设置事务是否自动提交--false
conn.setAutoCommit(false);
//这里只是简单的举个例子,实际上还要考虑账户余额够不够等条件
//从鑫鑫的账户扣除998
String sql = "update Account set money= money-998 where name='鑫鑫'";
st.execute(sql);
//System.out.println(1/0);//一旦发生异常,后面没有机会执行
//苍苍的余额+998
sql = "update Account set money = money+998 where name='苍苍'";
st.execute(sql);
//
conn.commit();//提交事务
5.连接池
连接池思想其实就是养鱼思想,需要用的时候从池子里取出来,不需要用的时候就放进池子养着。
需要用到的两个jar包:commons-dbcp-1.3 commons-pool-1.5.6
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-pool/commons-pool -->
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.5.6</version>
</dependency>
是否使用连接词的差异:
不使用连接池:Connection conn = DriverManager.getConnection 就是说Connection对象是Manager创建的。
使用连接池:conn = ds.getConnection() Connection对象是从DataSource里面拿的对象,DataSource返回去找数据库,所以我们需要把用户名和密码给连接池,连接池帮我们从数据库拿连接。使用连接池后释放资源close(),它并不是将资源关闭了,而是将资源重新放进连接池中,以便后续使用。
static Properties p = new Properties();
static DataSource ds;
static{//静态代码块,类加载的时候直接加载一次
try {
//配置对象加载流资源读取db.properties文件
p.load( Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties") );
/**
* 连接池工厂,创建链接池对象
* 工厂自己的内部:回去读取配置对象中的信息p.getProperties(String key)
* value = properties.getProperty(PROP_DRIVERCLASSNAME);
* //工厂的底层代码,我就是要通过key的名字叫做driverClassName
* p.getPropertie("driverClassName")
* p.getPropertie("url")
* p.getPropertie("username")
* p.getPropertie("password")
*/
ds = BasicDataSourceFactory.createDataSource(p);
} catch (Exception e) {
e.printStackTrace();
}
连接池有三个值(都是可以自己设置的):
1.连接词都有时刻开放的窗口数;
2.连接池也有最大运营的窗口数;
3.连接池不能时时刻刻开放,会占用资源,只要有一段时间不用,它会自动关闭。
<!-- 连接池参数 -->
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">10</property>
<property name="checkoutTimeout">3000</property>
6.抽取Base工具类
在增删改的方法中,其实本质上代码是一样的,区别就是SQL语句不同,SQL语句不同参数也不一致,可以将代码简化。
Dao层
public interface BaseDao {
void excuteUpdate(String sql,Object...val);
}
实现层:
public class BaseDaoImpl implements BaseDao{
@Override
public void excuteUpdate(String sql, Object... val) {
//第一步加载驱动,获取连接对象
Connection conn = null;
PreparedStatement ps = null;
try {
conn = JdbcUtil.getConnerction();
//将sql语句传入对象中
ps = conn.prepareStatement(sql);
//循环遍历 将val数组的每一个值传入到sql语句填充里面的问号
for (int i = 0 ; i < val.length ; i++){
//因为i从0开始计算的,但是parameterIndex的索引是从1开始的,所以需要i+1,将val数组取到的值赋值进去
ps.setObject(i+1,val[i]);
}
ps.execute();
}catch (Exception e){
e.printStackTrace();
}
}
}
得到的效果:简化后的增删改查代码
/**
* 增加数据
* @param person
*/
@Override
public void add(Person person) {
String sql = "INSERT INTO person (id, name, age, phone, sex) VALUES (default,?,?,?,?);";
super.excuteUpdate(sql,person.getName(),person.getAge(),person.getPhone(),person.isSex());
}
Day31-Html&Css
1.JavaWeb
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M36FPiZz-1596204776001)(C:\Users\吴永鑫\AppData\Roaming\Typora\typora-user-images\image-20200715195912420.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3mb9uqjR-1596204776005)(C:\Users\吴永鑫\AppData\Roaming\Typora\typora-user-images\image-20200715195931920.png)]
2.Html
概念:超文本标记语言,静态页面的编写技术。
用法:熟练查找W3C文档。
表格:
table,tr——行 td——列
<!--colspan代表占用几个行空格-->
<td colspan="2">11</td>
11
图片/超链接
<body>
<!--src代表图片的路径
./ ----代表本层结构内 同级别的 譬如文件夹css与文件夹img就是同一个级别
../ ---- 代表上一层,譬如文件夹CSS的上一级就是Day31-Html+css
-->
<img src="./img/2.jpeg" alt="图片加载失败" width="400px" height="600px"/>
<!-- a标签就是一个超链接标签,href属性一般是一个网址的连接。-->
<a href="http://www.baidu.com">百度搜索</a>
</body>
form表单
form定义一个表单,里面有action和method属性
action——定义表单内数据提交的位置,接地气的可以理解为本表单点了登录后跳转的页面
method——有get和post两种请求方式,
get——通过url提交数据,提交文件的大小也有被限制,不安全。
post——数据不会出现在地址栏,没有文件大小限制,安全。一般用post
当用get提交数据时,要想让数据体现在url地址上,表单内每个元素都必须要用name属性
<form action="#" method="get">
<!--form表单内基本用input标签 用type=?代表标签的元素属性(文本/图片/单选/多选/必选等等)-->
账号:<input type="text" name="username" value="admin"/><!--value代表默认值,即文本框的默认值时admin--><br />
<!--text表示文本-->
密码:<input type="text" name="password" /><br />
<!--radio表示单选框-->
性别: <input type="radio" name="sex" value="1"/>男 <input type="radio" name="sex" value="2"/>女<br />
<!--checkbox表示多选框-->
喜好:<input type="checkbox" name="hobby"/>唱歌 <input type="checkbox" name="hobby"/>篮球
<input type="checkbox" name="hobby"/>爬山<br/>
<!--hidden表示隐藏于,value表示值。隐藏提交的值-->
<input type="hidden" value="123456"/><br/>
<!--button代表普通按钮,一般时在动态页面JS用的-->
<input type="button" value="普通按钮"/><br/>
<!--提交按钮,点了就会跳到action属性里面的url-->
<input type="submit" value="登录"/><br/>
<!--重置信息按钮-->
<input type="reset" value="重置"/><br/>
<!--图片连接-->
<input type="image" src="img/1.jpeg" width="40px" height="50px"/><br/>
<!--文件上传-->
<input type="file" /><br/>
<!--多文本行域
style="resize: none —— 固定文本框不动
-->
个人简介:<textarea cols="20" rows="5" style="resize: none;"></textarea><br />
<!--下拉框-->
<select name="city">
<option>武汉</option>
<option>成都</option>
<option>重庆</option>
<option>浙江</option>
</select>
<select>
<option>江夏区</option>
<option>汉口区</option>
<option>黄陂区</option>
<option>江汉区</option>
</select>
3.Css
所谓CSS,直白点就是装饰页面,给界面加上格式
css语法: 样式属性:属性值
css三种写法:
1.行内样式:只对当前标签内有效
2.内部样式 :style标签写样式
3.外部引入:外部有一个写好的css文件,使用link标签将次css样式和需要的网页连接起来
css选择器:就是根据标签的属性/名字等等来选择同类标签,配合css给页面增加格式。