JavaScript一 Li.066

JavaScript JS的2种引入方式 直接在页面写 在页面引入 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>快速入门</title> </head> <body> <button id="btn">点我呀</button> <!--引入js的方式一: 内部方式--> <script type="text/javascript"> document.getElementById("btn").onclick = function (){ alert("点我干嘛") } </script> <script src="js/my.js"></script> </body> </html> 输入输出语句 输入框 prompt(“提示内容”); 弹出警告框 alert(“提示内容”); 控制台输出 console.log(“显示内容”); 页面内容输出 document.write(“显示内容”); <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>输入输出语句</title> </head> <body> <script> /* * 输入框 * prompt("提示内容"); * 弹出警告框 * alert("提示内容"); * 控制台输出 * console.log("显示内容"); * 页面内容输出 * document.write("显示内容"); */ prompt("请输入数据") alert("hello") console.log("打印logo") document.write("DaDaDa...") document.write("<br/>") document.write("DaDa") document.write("<h1>Hello</h1>") </script> </body> </html> 变量和常量 JavaScrip属于弱类型语言, 定义变量时不区分具体的数据类型 定义局部变量 let 变量名 = 值 定义全局变量 变量名 = 值; 定义常量 const 常量名= 值 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>变量和常量</title> </head> <body> <script> // 1. 定义局部变量 let name = "张三"; let age = 23; document.write(name+", "+ age) document.write("<br/>") // 2. 定义全局变量 { let l1 = "aa"; l2 = "bb"; } // document.writeln(l1) document.writeln(l2) document.write("<br/>") // 3. 定义常量 const PI = 3.1415926 // PI = 3.15 document.write(PI) </script> </body> </html> 原始数据类型 数据类型 说明 boolean 布尔类型,true或false null 声明null值的声明关键字 undefined 代表变量未定义 number 整数或浮点数 string 字符串 bigint 大整数,例如let num=10n; typeof用于判断变量的数据类型 let age=18; document.write(typeof(age)); //number <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>typeof方法</title> </head> <body> <script> let l1 = true document.write(typeof (l1)) document.write("<br/>") let l2 = null document.write(typeof (l2)) document.write("<br/>") let l3 document.write(typeof (l3)) document.write("<br/>") let l4 = 10 document.write(typeof (l4)) document.write("<br/>") let l5 = "hello" document.write(typeof (l5)) document.write("<br/>") let l6 = 100n document.write(typeof (l6)) document.write("<br/>") </script> </body> </html> 算数运算符 算术运算符 运算符 说明 + 加法运算 - 减法运算 * 乘法运算 / 除法运算 % 取余数 ++ 自增 -- 自减 赋值运算符 运算符 说明 = 将箱封号右边的值赋值给箱封号左边的变量 += 想回后赋值 -= 相减后赋值 *= 相乘后赋值 /= 相除后赋值 %= 取余数后赋值 比较运算符 运算符 说明 == 判断值是否相等 === 判断数据类型和值是否相等 > 大于 >= 大于等于 < 小于 <= 小于等于 != 不等于 逻辑运算符 运算符 说明 && 逻辑与,并且 || 逻辑或,或者 ! 取反 三元运算符 三元运算符格式 (比较表达式)?表达式1:表达式2; 执行流程 如果比较表达为true, 则取表达式1 如果比较表达为false, 则取表达式2 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>运算符</title> </head> <body> <script> let num = "10" // 和字符之间的+号, 拼接, 其他符号则把字符转成number运算 document.write(num + 5) document.write("<br/>") document.write(num + "5") document.write("<br/>") document.write(num - 5) document.write("<br/>") document.write(num * 5) document.write("<br/>") let num2 = 10 document.write(num == num2) document.write("<br/>") document.write(num === num2) document.write("<br/>") </script> </body> </html> JavaScrip的 流程控制和循环语句 if switch for while <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>流程控制和循环语句</title> </head> <body> <script> // if 语句 let month = 10 if(month >= 3 && month <= 5){ document.write("春季") } else if( month >= 6 && month <= 6){ document.write("夏季") } else if( month >= 9 && month <= 11) { document.write("秋季") } else if( month == 12 || month == 1 || month == 2) { document.write("冬季") } else { document.write("月份有误") } document.write("<br/>") // switch 语句 switch (month){ case 3: case 4: case 5: document.write("春季") break case 6: case 7: case 8: document.write("夏季") break case 9: case 10: case 11: document.write("秋季") break case 12: case 1: case 2: document.write("冬季") break default: document.write("月份有误") } document.write("<br/>") // for for(let i=1;i<=5;i++){ document.write(i+"<br/>") } // while let n =6 while (n <= 10){ document.write(n+"<br/>") n++ } </script> </body> </html> 数组 数组的使用Java中的数据基本一致, 但是在JavaScript中的数据更加灵活, 数据类型和长度都没有限制 定义格式 let 数组名 = [元素1,元素2,…]; 索引范围 从0开始, 最大到数组长度-1 数组长度 数组名.length 数组高级运算符… 数组复制 合并数组 字符串转数组 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>数组</title> </head> <body> <script type="text/javascript"> // 定义数组 let arr = [10,20,30] for(let i=0; i < arr.length; i++){ document.write(arr[i]) document.write("<br/>") } document.write("=======================<br/>") arr[3] = 40 for(let i=0; i < arr.length; i++){ document.write(arr[i]) document.write("<br/>") } document.write("=======================<br/>") // 数组高级运算符: ... // 复制数组 let arr2 = [...arr] for(let i=0; i < arr2.length; i++){ document.write(arr2[i]) document.write("<br/>") } document.write("=======================<br/>") // 合并数据 let arr3 = [40,50,60]; let arr4 = [...arr2,...arr3] for(let i=0; i < arr4.length; i++){ document.write(arr4[i]) document.write("<br/>") } for(var i of arr4){ document.write(i) document.write("<br/>") } document.write("=======================<br/>") // 字符串转成数组 let arr5 = [..."heima"] for(var i of arr5){ document.write(i) document.write("<br/>") } </script> </body> </html> 函数 函数类似于java中的方法, 可以将一些代码进行抽取, 达到复用的效果 定义格式 function 方法名(参数列表){方法体 return 返回值} 有返回值, 可以写 无返回值, 则不需要写 可变参数 function 方法名(…参数名){ 方法体; return 返回值 } 匿名函数 function(参数列表){ 方法体; } <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>函数</title> </head> <body> <script > // 无参无返回值的函数 function println(){ document.write("Hello JS"+"<br/>") } println() // 有参 有返回值方法 function getSum(num1,num2){ return num1 + num2; } let sum = getSum(10,20); document.write(sum+"<br/>") // 可变参数, 对n个数字进行求和 function getSum(...params){ let ss = 0 for(let i=0; i <params.length; i++){ ss+=params[i] } return ss; } let sum2 = getSum(10,20, 20) document.write(sum2) // 匿名函数 let fun = function(){ document.write("hello") } fun() </script> </body> </html> DOM DOM(Document Object Model):文档对象模型 ...

November 14, 2021&nbsp;·&nbsp;7 分钟&nbsp;·&nbsp;Lizicai

MyBatis框架三 Li.065

注解开发MyBatis 操作 创建接口和查询方法 在核心配置文件中配置映射关系 编写测试类 package com.lizicai.mapper; import com.lizicai.bean.Student; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; import java.util.List; public interface StudentMapper { // 查询 @Select( "SELECT * FROM student") public abstract List<Student> selectAll(); // 插入数据 @Insert("INSERT INTO student VALUES (#{id},#{name},#{age})") public abstract Integer insert(Student stu); // 修改数据 @Update("UPDATE student SET name=#{name},age=#{age} WHERE id=#{id}" ) public abstract Integer update(Student stu); // 删除数据 @Delete("DELETE FROM student WHERE id=#{id}") public abstract Integer delete(Integer id); } <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTA Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 数据库账号配置--> <properties resource="jdbc.properties"></properties> <!-- 配置log4j--> <settings> <setting name="logImpl" value="log4j"/> </settings> <!-- 起别名 --> <typeAliases> <package name="com.lizicai.bean"/> </typeAliases> <!-- 集成分页助手插件 --> <plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin> </plugins> <environments default="mariadb"> <environment id="mariadb"> <!-- 事务管理, 默认采用JDBC默认的事务--> <transactionManager type="JDBC"></transactionManager> <!-- dataSource数据源信息 type属性 连接池--> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> <environment id="mariadb2"> <transactionManager type="JDBC"></transactionManager> <dataSource type="POOLED"> <property name="driver" value="org.mariadb.jdbc.Driver"/> <property name="url" value="jdbc:mariadb://192.168.0.100:3306/db2"/> <property name="username" value="root"/> <property name="password" value="rootPassword"/> </dataSource> </environment> </environments> <mappers> <!-- 配置映射关系--> <package name="com.lizicai.mapper"/> </mappers> </configuration> package com.lizicai.test; import com.lizicai.bean.Student; import com.lizicai.mapper.StudentMapper; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.jupiter.api.Test; import java.io.IOException; import java.io.InputStream; import java.util.List; public class Test01 { @Test public void selectAll() throws IOException { InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); SqlSession sqlSession = sqlSessionFactory.openSession(true); StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); List<Student> list = mapper.selectAll(); for(Student c : list){ System.out.println(c); } sqlSession.close(); is.close(); } @Test public void insert() throws IOException { InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); SqlSession sqlSession = sqlSessionFactory.openSession(true); StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); Student stu = new Student(9,"李大刀",20); Integer result = mapper.insert(stu); System.out.println(result); sqlSession.close(); is.close(); } @Test public void update() throws IOException { InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); SqlSession sqlSession = sqlSessionFactory.openSession(true); StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); Student stu = new Student(9,"李大刀",22); Integer result = mapper.update(stu); System.out.println(result); sqlSession.close(); is.close(); } @Test public void delete() throws IOException { InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); SqlSession sqlSession = sqlSessionFactory.openSession(true); StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); Integer result = mapper.delete(9); System.out.println(result); sqlSession.close(); is.close(); } } 一对一 环境准备 ...

November 4, 2021&nbsp;·&nbsp;7 分钟&nbsp;·&nbsp;Lizicai

MyBatis框架二 Li.064

接口代理方式实现Dao层 接口代理方式-实现规则 传统方式实现Dao 层,我们既要写接口,还要与实现类。而MyBatis框架可以帮助我们省略编写 Dao 层接口实现类的步骤 程序员只需要编写接口,由MyBatis 框架根据接口的定义来创建该接口的动态代理对象。 实现规则 映射配置文件中的名称空间必须和 Dao 层接口的全类名相同。 映射配置文件中的增删改查标签的 id 属性必须和 Dao 层接口的方法名相同。 映射配置文件中的增删改查标签的 parameterType 属性必须和 Dao 层接口方法的参数相同。 映射配置文件中的增删改查标签的 resultType 属性必须和 Dao 层接口方法的返回值相同。 获取动态代理对象 SqlSession功能类中的getMapper()方法 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTA Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- mapper: 核心根标签 namespace属性: 名称空间 --> <mapper namespace="com.lizicai.mapper.StudentMapper"> <!-- select: 查询功能的标签 id属性: 唯一标识 resultType属性: 指定结果映射对象类型 parameterType属性: 指定参数映射对象类型 --> <select id="selectAll" resultType="student"> SELECT * FROM student </select> <select id="selectById" resultType="student" parameterType="int"> SELECT * FROM student WHERE id = #{id} </select> <insert id="insert" parameterType="student"> INSERT INTO student VALUES (#{id},#{name},#{age}) </insert> <update id="update" parameterType="student"> UPDATE student SET name=#{name},age=#{age} WHERE id=#{id} </update> <delete id="delete" parameterType="int"> DELETE FROM student WHERE id=#{id}; </delete> </mapper package com.lizicai.service.impl; import com.lizicai.bean.Student; import com.lizicai.mapper.StudentMapper; import com.lizicai.service.StudentService; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; import java.util.List; public class StudentServiceImpl implements StudentService { // 查询全部 @Override public List<Student> selectAll() { List<Student> list = null; InputStream is = null; SqlSession sqlSession = null; try{ // 1. 加载核心配置文件 is = Resources.getResourceAsStream("MyBatisConfig.xml"); // 2. 获取SqlSession工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); // 3. 通过工厂对象获取SqlSession对象 sqlSession = sqlSessionFactory.openSession(true); // 4. 获取StudentMapper接口的实现类对象 StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // 5. 通过实现类对象调用方法, 接收结果 list = mapper.selectAll(); }catch (IOException e){ e.printStackTrace(); } finally { // 6. 释放资源 if( sqlSession != null){ sqlSession.close(); } if( is != null){ try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } // 7. 返回结果 return list; } // 根据id查询 @Override public Student selectById(Integer id) { Student stu = null; InputStream is = null; SqlSession sqlSession = null; try{ // 1. 加载核心配置文件 is = Resources.getResourceAsStream("MyBatisConfig.xml"); // 2. 获取SqlSession工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); // 3. 通过工厂对象获取SqlSession对象 sqlSession = sqlSessionFactory.openSession(true); // 4. 获取StudentMapper接口的实现类对象 StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // 5. 通过实现类对象调用方法, 接收结果 stu = mapper.selectById(id); }catch (IOException e){ e.printStackTrace(); } finally { // 6. 释放资源 if( sqlSession != null){ sqlSession.close(); } if( is != null){ try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } // 7. 返回结果 return stu; } @Override public Integer insert(Student stu) { Integer result = null; InputStream is = null; SqlSession sqlSession = null; try{ // 1. 加载核心配置文件 is = Resources.getResourceAsStream("MyBatisConfig.xml"); // 2. 获取SqlSession工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); // 3. 通过工厂对象获取SqlSession对象 sqlSession = sqlSessionFactory.openSession(true); // 4. 获取StudentMapper接口的实现类对象 StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // 5. 通过实现类对象调用方法, 接收结果 result = mapper.insert(stu); }catch (IOException e){ e.printStackTrace(); } finally { // 6. 释放资源 if( sqlSession != null){ sqlSession.close(); } if( is != null){ try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } // 7. 返回结果 return result; } @Override public Integer update(Student stu) { Integer result = null; InputStream is = null; SqlSession sqlSession = null; try{ // 1. 加载核心配置文件 is = Resources.getResourceAsStream("MyBatisConfig.xml"); // 2. 获取SqlSession工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); // 3. 通过工厂对象获取SqlSession对象 sqlSession = sqlSessionFactory.openSession(true); // 4. 获取StudentMapper接口的实现类对象 StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // 5. 通过实现类对象调用方法, 接收结果 result = mapper.update(stu); }catch (IOException e){ e.printStackTrace(); } finally { // 6. 释放资源 if( sqlSession != null){ sqlSession.close(); } if( is != null){ try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } // 7. 返回结果 return result; } @Override public Integer delete(Integer id) { Integer result = null; InputStream is = null; SqlSession sqlSession = null; try{ // 1. 加载核心配置文件 is = Resources.getResourceAsStream("MyBatisConfig.xml"); // 2. 获取SqlSession工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); // 3. 通过工厂对象获取SqlSession对象 sqlSession = sqlSessionFactory.openSession(true); // 4. 获取StudentMapper接口的实现类对象 StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // 5. 通过实现类对象调用方法, 接收结果 result = mapper.delete(id); }catch (IOException e){ e.printStackTrace(); } finally { // 6. 释放资源 if( sqlSession != null){ sqlSession.close(); } if( is != null){ try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } // 7. 返回结果 return result; } } 动态SQL 动态SQL介绍 MyBatis映射配置文件中, 前面SQL都是简单的, 有些业务逻辑复杂时, SQL是动态变化, 此时前面学习的SQL就不能满足要求了 多条件查询 SELECT * FORM student WHERE id=? AND name=? AND age=?; SELECT * FORM student WHERE id=? AND name=?; 动态SQL标签 : 条件判断标签 : 循环遍历标签 标签 : 条件标签. 如果有动态条件, 则使用访标签代替where关键字 : 条件判断标签 <if test="条件判断"> 查询条件拼接 </if> <select id="selectCondition" resultType="student" parameterType="student"> SELECT * FROM student <where> <if test="id != null"> id=#{id} </if> <if test="name != null"> AND name=#{name} </if> <if test="age != null"> AND age=#{age} </if> </where> </select> @Test public void selectCondition() throws IOException { InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); SqlSession sqlSession = sqlSessionFactory.openSession(true); StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); Student stu = new Student(); // stu.setId(2); stu.setName("李四"); stu.setAge(24); List<Student> list = mapper.selectCondition(stu); for(Student student : list){ System.out.println(student); } sqlSession.close(); is.close(); } 标签 foreach : 循环遍历标签, 适用于多个参数或者的关系 <froeach colloction="" open="" close="" item="" separator=""> 获取参数 </froeach> 属性 colloction: 参数容器,(list 集合, array 数组) open: 开始的SQL语句 close: 结束的SQL语句 item: 参数变量名 separator: 分隔符 <select id="selectByIds" resultType="student" parameterType="list"> SELECT * FROM student <where> <foreach collection="list" open="id IN (" close=")" item="id" separator=","> #{id} </foreach> </where> </select> StudentMapper ...

November 3, 2021&nbsp;·&nbsp;9 分钟&nbsp;·&nbsp;Lizicai

MyBatis框架一 Li.063

MyBatis 介绍 MyBatis 是一个优秀的基于Java 的特久层框架,它内部封装了JDBC,使开发者只需要关注SQL语句本身, 而不需要花费精力去处理加载驱动、创建连接、创建执行者等复杂的操作。 MyBatis通过xml 或注解的方式将要执行的各种Statement 配置起来,并通过Java对象和 Statement中 SQL 的动态参数进行映射生成最终要执行的SQL 语句。 最后MyBatis 框架执行完 SQL 并将结果映射为 Java 对象并返回。采用ORM 思想解决了实体和数据库映射的问题,对JDBC 进行了封装,屏蔽了 JDBC API 底层访问细节,使我们不用与JDBC API打交道,就可以 完成对数据库的持久化操作。 MyBatis 使用示例 导入mariadb-java-client-2.7.4.jar和mybatis-3.5.7.jar CREATE DATABASE db1; use db1; create table student( id int auto_increment primary key , NAME VARCHAR(20), age int ); INSERT INTO student VALUES (null,'张三',23),(null,'李四',24),(null,'王五',25); public class Student { private Integer id; private String name; private Integer age; ...略 } package com.lizicai.dao; import com.lizicai.bean.Student; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; import java.util.List; public class StudentTest01 { /** * 查询全部 */ public static void main(String[] args) throws IOException { StudentTest01 s = new StudentTest01(); s.selectAll() ; } public void selectAll() throws IOException { // 1. 加载核心配置文件 InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); // 2.获取sqlSession工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); // 3.获取sqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); // 4. 获取执行结果 List<Student> list = sqlSession.selectList("StudentMapper.selectAll"); // 5.打印结果 for(Student stu : list){ System.out.println(stu); } // 6. 关闭资源 sqlSession.close(); is.close(); } } <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTA Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <environments default="mariadb"> <environment id="mariadb"> <transactionManager type="JDBC"></transactionManager> <dataSource type="POOLED"> <property name="driver" value="org.mariadb.jdbc.Driver"/> <property name="url" value="jdbc:mariadb://192.168.0.100:3306/db1"/> <property name="username" value="root"/> <property name="password" value="rootPassword"/> </dataSource> </environment> </environments> <mappers> <mapper resource="StudentMapper.xml" /> </mappers> </configuration> MyBatis 相关API Resources: org.apache.ibatis.io.Resources 核心方法 返回值 方法名 说明 InputStream getResourceAsStream(String.fileName) 通过类加载器返回指定资源的字节输入流 SqlSessionFactoryBuilder: org.apache.ibatis.session.SqlSessionFactoryBuilder 获取SqlSessionFactory工厂对象的功能类 核心方法 返回值 方法名 说明 SqlSessionFactory build(InputStream.is) 通过指定资源字节输入流获取SqlSession工厂对象 SqlSessionFactory: org.apache.ibatis.session.SqlSessionFactory: 获取SqlSession构建者对象的工厂接口 核心方法 返回值 方法名 说明 SqlSession openSession() 获取SqlSession构建对象,并开户手动提交事务 SqlSession openSession(boolean.autoCommit) 获取SqlSession构建者对象,如果参数为true,则开户自动提交事务 SqlSession: org.apache.ibatis.session.SqlSession 构建者对象接口. 用于执行SQL, 管理事务, 接口代理. 返回值 方法名 说明 List<E> selectList(String.statement,Object.paramter) 执行查询语句,返回List集合 T selectOne(String.statement,Object.paramter) 执行查询语句,返回一个结果对象 int insert(String.statement,Object.paramter) 执行新增语句,返回影响行数 int update(String.statement,Object.paramter) 执行修改语句,返回影响行数 int delete(String.statement,Object.paramter) 执行删除语句,返回影响行数 void commit() 提交事务 void rollback() 回滚事务 T getMapper(Class<T>.cls) 获取指定接口的代理实现类对象 void close() 释放资源 public class Student { private Integer id; private String name; private Integer age; ...

October 29, 2021&nbsp;·&nbsp;7 分钟&nbsp;·&nbsp;Lizicai

JDBC数据库连接三 Li.062

自定义JDBC框架 使用JDBC过程中有大量的重复代码, 核心功能仅仅执行一条SQL语句, 所以可以抽取一个JDBC模板类, 来封装一些方法(update query). 专门帮我们执行增删改查SQL语句. 将之前那些重复的操作, 都抽取到模板类中的方法里, 就能大简化使用步骤 源信息 DataeBaseMetaData: 数据库的源信息 java.sql.DataBaseMetaData 封装了整个数据库的综合信息 例如 String getDatabaseProductName(): 获取数据库产品的名称 例如int getDatabaseProductVersion: 获取数据库产品的版本号 ParameterMetaData: 参数源信息 java.sql.ParameterMetaData 封装的是预编译执行者对象中每个参数的类型和属性, 这个对象可以通过预编译执行者对象中的getParameterMetaData()方法来获取 int getParameterCount() 用于获取SQL语句中的参数个数 ResultSetMetaData: 结果集的源信息 java.sql.ResultSetMetaData: 封装的是结果集对象中列的类型和属性, 这个对象可以通过结果集对象中的getMetaData()方法来获取 int getColumnCount() 用于获取列的总数, String getColumnName(int i)用于获取列名 package com.test005; import com.lizicai.utils.DataSourceUtils; import javax.sql.DataSource; import java.io.IOException; import java.sql.*; public class JDBCTemplate { // 1. 定义参数变量(数据源, 连接对象, 执行者对象, 结果集对象 private DataSource dataSource; private Connection con; private PreparedStatement pst; private ResultSet rs; // 2. 通过有参构造为数据源赋值 public JDBCTemplate(DataSource dataSource){ this.dataSource = dataSource; } // 3. 定义update方法, 参数 sql语句 sql语句中的参数 public int update(String sql, Object... objs){ int result = 0; try { con = dataSource.getConnection(); pst = con.prepareStatement(sql); ParameterMetaData parameterMetaData = pst.getParameterMetaData(); int count = parameterMetaData.getParameterCount(); if( count != objs.length){ throw new RuntimeException("参数个数不匹配"); } for(int i=0; i< objs.length;i++){ pst.setObject(i+1,objs[i]); } result = pst.executeUpdate(); } catch (Exception e) { e.printStackTrace(); } finally { DataSourceUtils.close(con, pst); } return result; } } package com.test005; import com.lizicai.utils.DataSourceUtils; import org.junit.Test; public class JDBCTemplateTest1 { private JDBCTemplate template = new JDBCTemplate(DataSourceUtils.getDataSource()); @Test public void insert(){ String sql = "INSERT INTO student VALUES (?,?,?,?)"; Object[] params = {5,"周七",27,"1997-07-07"}; int result = template.update(sql, params); if(result != 0){ System.out.println("添加成功"); } else { System.out.println("添加失败"); } } @Test public void update(){ String sql = "UPDATE student SET age=? WHERE name=?"; Object[] params = {37,"周七"}; int result = template.update(sql, params); System.out.println(result); } @Test public void delete(){ String sql = "DELETE FROM student where name=?"; Object[] params = {"周七"}; int result = template.update(sql, params); System.out.println(result); } } 查询功能-框架编写 查询一条记录并封装对象的方法: queryForObject() ...

October 27, 2021&nbsp;·&nbsp;5 分钟&nbsp;·&nbsp;Lizicai

JDBC数据库连接二 Li.061

数据库连接池 数据库连接池 数据库连接池负责分配,管理和释放数据库连接,它允许应用程序重复使用一个现在的数据库连接,而不是再重新建立一个. 这项技术能明显提高对数据库操作的性能 DataSource接口概述 javax.sql.DataSource接口: 数据源(数据库连接池). Java官方提供的数据库连接池规范(接口) 如果想完成数据库连接池技术, 就必须实现DataSource接口 核心功能: 获取数据库连接对象: Connection getConnection() 自定义数据库连接池 定义一个类, 实现DataSource接口 定义一个容器, 用于保存多个Connection连接对象 定义静态代码块, 通过JDBC工具类获取10个连接保存到容器中 重写getConnection方法, 从容器中获取一个连接并返回 定义getSize方法, 用于获取窗口的大小并返回 package com.test001; import com.lizicai.utils.JDBCUtils; import javax.sql.DataSource; import java.io.PrintWriter; import java.sql.Connection; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.logging.Logger; public class MyDataSource implements DataSource { // 1. 准备窗口, 用于保存多个连接对象, 变成线程安全的 private static List<Connection> pool = Collections.synchronizedList(new ArrayList<>()); // 2. 定义代码块, 通过工具类获取10个连接对象 static { for(int i=0;i<10;i++){ Connection con = JDBCUtils.getConnection(); pool.add(con); } } //3 重写getConnection() , 用于获取一个连接对象 @Override public Connection getConnection() throws SQLException { if( pool.size()> 0){ Connection con = pool.remove(0); return con; } else { throw new RuntimeException("连接数量已用尽"); } } // 4. 定义getSize方法, 获取连接池窗口的大小 public int getSize(){ return pool.size(); } } package com.test001; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class MyDataSourceTest { public static void main(String[] args) throws SQLException { MyDataSource pool = new MyDataSource(); System.out.println(pool.getSize()); Connection con = pool.getConnection(); String sql = "SELECT * FROM student"; PreparedStatement pst = con.prepareStatement(sql); ResultSet rs = pst.executeQuery(); while (rs.next()){ System.out.println(rs.getInt("sid")+"\t"+rs.getString("NAME") +"\t"+rs.getInt("age")+"\t"+rs.getDate("birthday")); } rs.close(); pst.close(); con.close(); System.out.println(pool.getSize()); } } 归还方式 归还数据库连接的方式 继承方式 装饰设计模式 我在适配器设计模式 动态 代理方式 归还方式 - 继承方式 继承方式归还数据库连接的思想。 通过打印连接对象,发现 DriverManager 获取的连接实现类是 JDBC4Connection 那我们就可以自定义一个类,继承JDBC4Connection这个类,重写closeQ 方法,完成连接对象的归还 继承方式归还数据库连接的实现步骤。 定义一个类,继承JDBC4Connection。 定义 Connection 连接对象和连接池容器对象的成员变量。 通过有参构造方法完成对成员变量的赋值。 重写cose 方法,将连接对象添加到池中。 继承方式日还数据库连接存任的问题。 通过查看 JDBC 工具类获取连接的方法发现:我们星然白定义了一个子类,完成了归还连接的操作。但是 DriverManager 获取的还是JDBC4Connection这个对象,并不是我们的子类对象,而我们又不能整体去修改驱动包中类的功能,所继承这种方式行不通! 归还连接 - 装饰设计模式 装饰设计模式日还数据库连接的思想。 我们可以自定义一个类,实现 Connection接口。这样就具备了和 JDBC4Connection相同的行为了 重写close()方法,完成连接的归还。其余的功能还调用 mysql驱动包实现类原有的方法即可 装饰设计模式归还数据库连接的实现步骤。 定义一个类,实现 Connection 接口 定义 Connection 连接对象和连接池容器对象的成员变量 通过有参构造方法完成对成员变量的赋值 重写close()方法,将连接对象添加到池中 剩余方法,只需要调用mysql驱动包的连接对象完成即可 在自定义连接池中,将获取的连接对象通过自定义连接对象进行包装 装饰设计模式归还数据库连接存在的问题。 实现 Connection接口后,有大量的方法需要在自定义类中进行重写 package com.test002; import java.sql.*; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.Executor; /** * 1. 定义一个类, 实现Connection接口 * 2. 定义连接对象和连接池容器对象的成员变量 * 3. 通过有参构造方法为成员变量赋值 * 4. 重写close()方法, 完成归还连接 * 5. 剩余方法, 还是调用原有的连接对象中的功能即可 */ public class MyConnection2 implements Connection { private Connection con; private List<Connection> pool; public MyConnection2(Connection con, List<Connection> pool) { this.con = con; this.pool = pool; } @Override public void close() throws SQLException { pool.add(con); } } public class MyDataSource implements DataSource { //3 重写getConnection() , 用于获取一个连接对象 @Override public Connection getConnection() throws SQLException { if( pool.size()> 0){ Connection con = pool.remove(0); MyConnection2 myCon = new MyConnection2(con,pool); return myCon; } else { throw new RuntimeException("连接数量已用尽"); } } } 归还连接 - 适配器设计模式 适配器设计模式归还数据库连接的思想。 我们可以提供一个适配器类,实现 Connection 接口,将所有方法进行实现(除了close方法) 自定义连接类只需要继承这个适配器类,重写需要改进的close0 方法即可 适配器设计模式归还数据库连接的实现步骤。 定义一个适配器类, 实现 Connection 接口。 定义 Connection 连接对象的成员变量。 通过有参构造方法完成对成员变量的赋值。 重写所有方法(除了close), 调用mysq驱动包的连接对象完成即可。 定义一个连接类,继承适配器类。 定义 Connection 连接对象和连接池容器对象的成员变量,并通过有参构造进行赋值。 重写close()方法,完成归还连接。 在自定义连接池中,将获取的连接对象通过自定义连接对象进行包装。 适配器设计模式归还数据库连接存在的问题。 自定义连接类虽然很简洁, 但我在楼下器还是自己编写的, 也比较麻烦 public abstract class MyAdapter implements Connection { private Connection con; public MyAdapter(Connection con){ this.con = con; } //省略其他实现的方法 } package com.test002; import java.sql.Connection; import java.sql.SQLException; import java.util.List; public class MyConnection3 extends MyAdapter{ private Connection con; private List<Connection> pool; public MyConnection3(Connection con, List<Connection> pool) { super(con); this.con = con; this.pool = pool; } @Override public void close() throws SQLException { pool.add(con); } } 动态代理 动态代理: 在不改变目标对象方法的情况下对方法进行增强 组成 被代理对象: 真实的对象 代理对象: 内存的一个对象 要求 代理对象必须和被代理对象实现相同的接口 实现 Proxy.newProxyInstance() package com.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class Test { public static void main(String[] args) { Student stu = new Student(); stu.eat("饭"); stu.study(); /** * 要求: 在不改Student类中任何代码前提下, 通过study方法输出一句话 * 类加载器: 和被代理对象使用相同的类加载器 * 接口类型Class数组: 和被代理对象使用相同接口 * 代理规则: 完成代理增加的功能 */ StudentInterface proxyStu = (StudentInterface) Proxy.newProxyInstance(stu.getClass().getClassLoader(), new Class[]{StudentInterface.class}, new InvocationHandler() { /** * 执行student类中所有方法都会经过invoke方法 * 对method方法进行判断 * 如果是study, 则对其增强 * 如果不是, 还调用学生对象原的功能即可 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(method.getName().equals("study")){ System.out.println("学快点"); return null; } else { return method.invoke(stu, args); } } }); proxyStu.eat("米饭"); proxyStu.study(); } } 归还连接 - 动态代理方式 动态代理方式归还数据库连接的思想。 我们可以通过 Proxy 来完成对 Connection 实现类对象的代理 代理过程中判断如果执行的是 close 方法,就将连接归还池中。如果是其他方法则调用连接对象原来 的功能即可 动态代理方式归还数据库连接的实现步骤。 定义一个类,实现 DataSource接口 定义一个容器,用于保存多个Connection连接对象 定义静态代码块,通过JDBC工具类获取 10 个连接保存到容器中 重马getConnection 方法,从容器中获取一个连接 通过 Proxy 代理,如果是close 方法,就将连接归还池中。如果是其他方法则调用原有功能 定义 getsize 方法,用于获取容器的大小并返回 动态代理方式归还数据库连接存在的问题。 我们自己写的连接池技术不够完善,功能也不够强大 package com.test001; import com.lizicai.utils.JDBCUtils; import com.test002.MyConnection2; import com.test002.MyConnection3; import javax.sql.DataSource; import java.io.PrintWriter; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.sql.Connection; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.logging.Logger; public class MyDataSource implements DataSource { // 1. 准备窗口, 用于保存多个连接对象, 更改List为线程安全的 private static List<Connection> pool = Collections.synchronizedList(new ArrayList<>()); // 2. 定义代码块, 通过工具类获取10个连接对象 static { for(int i=0;i<10;i++){ Connection con = JDBCUtils.getConnection(); pool.add(con); } } // 动态代理归还Connection @Override public Connection getConnection() throws SQLException { if( pool.size()> 0){ Connection con = pool.remove(0); Connection proxyCon =(Connection) Proxy.newProxyInstance(con.getClass().getClassLoader(), new Class[]{Connection.class}, new InvocationHandler() { /** 执行Connection 实现类连接对象所有的方法都会经过invoke * 如果是close方法, 归还连接 * 如果不是, 直接执行连接对象原有的功能即可 * */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(method.getName().equals("close")){ pool.add(con); return null; } else { return method.invoke(con, args); } } }); return proxyCon; } else { throw new RuntimeException("连接数量已用尽"); } } // 4. 定义getSize方法, 获取连接池窗口的大小 public int getSize(){ return pool.size(); } @Override public Connection getConnection(String username, String password) throws SQLException { return null; } @Override public <T> T unwrap(Class<T> iface) throws SQLException { return null; } @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { return false; } @Override public PrintWriter getLogWriter() throws SQLException { return null; } @Override public void setLogWriter(PrintWriter out) throws SQLException { } @Override public void setLoginTimeout(int seconds) throws SQLException { } @Override public int getLoginTimeout() throws SQLException { return 0; } @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { return null; } } 使用C3P0数据库连接池的使用步骤 导入Jar包, c3p0-0.9.5.5.jar和mchange-commons-java-0.2.19.jar 导入配置文件到src目录下 创建C3P0连接池对象 获取数据库连接进行使用 C3P0下载, 开头/c3p0-bin/c3p0-0.9.5.5/c3p0-0.9.5.5.bin.zip ...

October 26, 2021&nbsp;·&nbsp;7 分钟&nbsp;·&nbsp;Lizicai

JDBC数据库连接一 Li.060

JDBC 的概念 JDBC的概念 JDBC(Java DataBase Connectivity Java数据库连接)是一种用于执行SQL语句的Java API, 可以为多种关系型数据库提供统一访问,它是由一组用Java语文编写的类和接口组成的 JDBC的本质 其实就是Java官方提供的一套规范(接口). 用于帮助开发人员快速实现不同关系型数据库的连接. JDBC 的快速入门程序 导入Jar包 注册驱动 获取数据库连接 获取执行者对象 执行SQL语句并返回结果 处理结果 释放资源 JDBC包下载 package com.lizicai.jdbc; import java.sql.*; public class JDBCDemo1 { public static void main(String[] args) throws ClassNotFoundException, SQLException { // 导入Jar包, 已导入 // 注册驱动, 也可以省略掉 Class.forName("org.mariadb.jdbc.Driver"); // 获取数据库连接 Connection connection = DriverManager.getConnection ("jdbc:mariadb://192.168.0.100:3306/db10", "root", "rootPassword"); // 获取执行者对象 Statement statement = connection.createStatement(); // 执行SQL语句并返回结果 String sql = "SELECT * FROM city"; ResultSet rs = statement.executeQuery(sql); // 处理结果 while (rs.next()){ System.out.println(rs.getInt("id")+","+rs.getString("NAME")+","+rs.getInt("VERSION")); } // 释放资源 connection.close(); statement.close(); } } DriverManager DriverManger驱动管理对象 注册驱动 注册给定的驱动程序: static void registerDriver(Driver driver) 写代码使用: Class.forName(“org.mariadb.jdbc.Driver”) 在org.mariadb.jdbc.Driver类中存在静态代码块 static { try { DriverManager.registerDriver(new Driver(), new DeRegister()); } catch (SQLException var1) { throw new RuntimeException("Could not register driver", var1); } } 不需要通过DriverManager调用静态方法registerDriver(),因为只要Driver类被使用,则会执行其静态代码块完成注册驱动 ...

October 24, 2021&nbsp;·&nbsp;7 分钟&nbsp;·&nbsp;Lizicai

MySQL数据库二 Li.059

视图 视图介绍 视图:是一种虛拟存在的数据表,这个虚拟表并不在数据库中实际存在。 作用:将一些较为复系的查询语句的结果,封装到-个虚拟表中,后期再有相同需求时,直接道询该虚拟表即可 # 准备数据 create database mydb5; use mydb5; create table country( id int primary key auto_increment, NAME varchar(30) ); insert into country values (null,'中国'),(null,'美国'),(null,'俄罗斯'); create table city( id int primary key auto_increment, NAME varchar(30), cid int, constraint cc_fk1 foreign key (cid) references country(id) ); insert into city values (null,'北京',1),(null,'上海',1),(null,'纽约',2),(null,"莫斯科",3); 视图的创建和查询 创建视图语法: create view 视图名称 [(列名列表)] as 查询语句; 查询视图语法: select * from 视图名称; ## 创建视图 create view city_country (city_id,city_name,country_name) as select c1.id,c1.NAME,c2.NAME from city c1, country c2 where c1.cid = c2.id; select * from city_country; 修改视图数据语法: update 视图名称 set 列名=值 where 条件; 修改视图的数据,原表的数据也会修改 ## 修改视图数据 update city_country set city_name ='深圳' where city_name='北京'; 修改视图结构语法: alter view 视图名称 (列名列表) as 查询语句; 删除视图语法: drop view [if exists] 视图名称; ## 修改视图结构 alter view city_country (city_id,city_name,NAME) as select c1.id,c1.NAME,c2.NAME from city c1, country c2 where c1.cid = c2.id; ## 删除视图 drop view if exists city_country; 数据库备份和恢复 备份-命令行方式 登录到MySQL服务器, mysqldump -uroot -p 数据库名称>文件保存路径(sql结尾文件) 恢复 登录MySQL数据库 删除已备份的数据库 重新创建名称相同的数据库 使用该数据库 导入文件执行: source 备份文件全路径 # 备份-命令行操作 mysqldump -uroot -p backupdatabase > /root/backupdatabase.sql # 恢复-命令行操作 mysqldump -uroot -p show databases; drop backupdatabase; create database backupdatabase; use backupdatabase; source /root/backupdatabase.sql; 备份-使用Datagrip Export with ‘mysqldump’ 恢复 使用Datagrip 删除已备份的数据库 重新创建名称相同的数据库 在数据库右键 Run SQL Script, 选择导出的文件.sql 存储过程和函数介绍 存储过程和函数是事先经过编译并存储在数据库的一段SQL说一句的集合 存储过程和函数的好处 提高代码的复用性 减少数据在数据库和应用服务器之间的传输, 提高效率 减少代码层面的业务处理 存储过程和函数的区别 存储函数必须有返回值 存储过程可以没有返回值 存储过程的创建和调用 创建存储过程 # 修改结束分隔符 delimiter $ # 创建存储过程 create procedure 存储过程名称(参数列表) BEGIN SQL语句列表; END$ # 修改结束分隔符 DELIMITER ; 调用存储过程 CALL 存储过程名称(实际参数); ## 存储过程数据准备 create database mydb6; use mydb6; create table student( id int primary key auto_increment, NAME varchar(20), age int, gender varchar(5), score int ); insert into student values (null,'张三',23,'男',95), (null,'李四',24,'男',98), (null,'王五',25,'女',100), (null,'赵六',26,'女',90); # 按照性别进行分级, 查询每组学生的总成绩. 按钮总成绩的升序排序 select gender,SUM(score) as getSum from student group by gender order by getSum asc; delimiter $ create procedure stu_group() BEGIN select gender,SUM(score) as getSum from student group by gender order by getSum asc; END $ delimiter ; call stu_group(); 存储过程的查看和删除 查看数据库中所有的存储过程 select * from mysql.proc where db=‘数据库名称’; 删除存储过程 drop procedure [if exists] 存储过程名称; # 查看存储过程 select * from mysql.proc where db='mydb6'; # 删除存储过程 drop procedure if exists stu_group; 存储过程语法 - 变量 定义变量: declare 变量名 数据类型 [default 默认值]; 变量赋值方式一: set 变量名=变量值; 变量赋值二: select 列名 into 变量名 from 表名 [where 条件]; # 按照性别进行分级, 查询每组学生的总成绩. 按钮总成绩的升序排序 select gender,SUM(score) as getSum from student group by gender order by getSum asc; delimiter $ create procedure stu_group() BEGIN select gender,SUM(score) as getSum from student group by gender order by getSum asc; END $ delimiter ; call stu_group(); # 查看存储过程 select * from mysql.proc where db='mydb6'; # 删除存储过程 drop procedure if exists stu_group; delimiter $ create procedure pro_test1() begin declare num int default 10; select num; end $ delimiter ; call pro_test1(); delimiter $ create procedure pro_test2() begin declare NAME varchar(10); set NAME='存储过程'; select NAME; end $ delimiter ; call pro_test2(); delimiter $ create procedure pro_test3() begin declare woman_sum_score,man_sum_score int; select sum(score) into woman_sum_score from student where gender='女'; select sum(score) into man_sum_score from student where gender='男'; select woman_sum_score,man_sum_score; end $ delimiter ; call pro_test3(); 存储过程语法 - if语句 if语句 if 判断条件1 then 执行的SQL语句1; [elseif 判断条件2 then 执行的SQL语句2] ... [else 执行的SQL语句n] end if; # 定义变量int 存储班级总成绩 # 定义vachar变量量, 用于存储分数描述 # 根据总成绩判断: 380分以上 学习优秀, 320~380 学习不错, 320以下 学习一般 delimiter $ create procedure pro_test4() begin declare all_sum_score int; declare info varchar(30); select sum(score) into all_sum_score from student; if all_sum_score>380 then set info='学习优秀'; elseif (all_sum_score<=380 && all_sum_score >=320) then set info='学习不错'; else set info='学习一般'; end if; select all_sum_score,info; end $ delimiter ; call pro_test4(); 存储过程语法 - 参数传递 存储过程的参数和返回值 delimiter $ create procedure 存储过程名称 ([IN|OUT|INOUT] 参数名 数据类型) begin SQL语句; end$ delimiter ; 参数 IN: 代表输入参数,需要由调用者传递实际数据(默认) OUT: 代表输入参数, 该参数可以作为返回值 INOUT: 代表既可以作为输入参数, 也可以作为输入参数 delimiter $ create procedure pro_test5(IN all_sum_score int,OUT info varchar(30)) begin if all_sum_score>380 then set info='学习优秀'; elseif (all_sum_score<=380 && all_sum_score >=320) then set info='学习不错'; else set info='学习一般'; end if; end $ delimiter ; call pro_test5(320,@info); call pro_test5((select sum(score) from student),@info); select @info; 存储过程语法 - while循环 while循环语法 初始化语句; while 条件判断语句 do 循环体语句; 条件控制语句; end while; delimiter $ create procedure pro_test6() begin declare result int default 0; declare i int default 1 ; while i < 101 do if i%2=0 then set result = result + i; end if; set i = i + 1; end while; select result; end $ delimiter ; call pro_test6; 存储函数 存储函数和存储过程是非常相似的, 区别在于存储函数必须有返回值 创建存储函数 delimiter $ create function 函数名称(参数列表) returns 返回值类型 begin SQL语句列表; RETURN结果; end$ delimiter ; 调用存储函数 select 函数名称(实际参数); 删除存储函数 drop function 函数名称; delimiter $ create function fun_test1() RETURNS int begin declare num int; select count(*) into num from student where score>95; return num; end $ delimiter ; select fun_test1(); drop function fun_test1; MySQL 触发器 触发器是与表有关的数据库对象, 可以在insert,update,delete之前或之后触发并执行触发器中定义的SQL语句. 这种特性可以协助应用系统在数据库端确保数据的完整性,日志记录,数据校验等操作. 使用别名NEW和OLD来引用触发器中发生变化的内容记录 触发器分类 触发器类型 OLD NEW INSERT型触发器 无(插入前无数据) NEW表示将要或者已经新增的数据 UPDATE型触发器 OLD表示修改之前的数据 NEW表示将要或已经修改后的数据 DELETE型触发器 OLD表示将要或者已经删除的数据 无(删除删除后状态无数据) 触发器的操作 创建触发器 delimiter $ create trigger 触发器名称 before|after insert|update|delete on 表名 fro each row begin 触发器要执行的功能; end $ delimiter ; # 数据准备 create database mydb7; use mydb7; create table account( id int primary key auto_increment, NAME varchar(20), money double ); insert into account values (null,'张三',1000),(null,'李四',1000); create table account_log( id int primary key auto_increment, operation varchar(20), operation_time datetime, operation_id int, operation_params varchar(200) ); # 插入触发器 delimiter $ create trigger account_insert after INSERT on account for each row begin insert into account_log values (null,'INSERT',now(),new.id, CONCAT('插入后{id=',new.id,',name=',new.NAME,',money=',new.money,'}')); end $ delimiter ; insert into account values (null,'王五',2000); select * from account; select * from account_log; # 更新触发器 delimiter $ create trigger account_update after UPDATE on account for each row begin insert into account_log values (null,'UPDATE',now(),new.id, CONCAT('更新前{id=',old.id,',name=',old.NAME,',money=',old.money,'}', '更新后{id=',new.id,',name=',new.NAME,',money=',new.money,'}')); end $ delimiter ; select * from account; update account set money=2000 where id=2; select * from account_log; # 删除触发器 delimiter $ create trigger account_delete after DELETE on account for each row begin insert into account_log values (null,'DELETE',now(),old.id, CONCAT('删除前{id=',old.id,',name=',old.NAME,',money=',old.money,'}')); end $ delimiter ; select * from account; delete from account where id=3; select * from account_log; 触发器的操作 查看触发器: show triggers; 删除触发器: drop trigger 触发器名称; # 查看触发器 show triggers ; # 删除触发器 drop trigger account_delete; MySQL 事务 事务: 一条或多条SQL语句组成一个执行单元, 其特点是这个单元要么同时成功要么同时失败 单元中的每条SQL语句都相互依赖, 形成一个整体 如果某条SQL语句执行失败或者出现错误, 那么整个单元就会撤回到事务最初的状态. 如果单元中所有的SQL语句都执行成功, 则事务就顺利执行. 事务的操作 开启事务: start transaction; 回滚事务: rollback; 提交事务: commit; # 准备数据 create database db8; use db8; create table account( id int primary key auto_increment, NAME varchar(20), money double ); insert into account values (null,'张三',1000),(null,'李四',1000); select * from account; # 开启事务 start transaction ; update account set money=money-500 where NAME='张三'; update account set money=money+500 where NAME='李四'; # 回滚事务 rollback ; # 提交事务 commit ; 事务的提交方式 事务提交方式的分类 自动提交(MySQL默认) 手动提交 查看事务提交方式 select @@autocommit; 修改事务提交方式 set @@autocommit=数字; # 查询事务的提交方式 select @@autocommit; # 修改事务的提交方式 # 默认是1, 不可修改 set @@autocommit=0; 事务的四大特征 原子性(Atomicity) 原子性是指事务包含的所有操作要么全部成功 ,要么全部失败回滚。 因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。 一致性(Consistency) 一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态。 也就是说一个事务执行之前和执行之后都必须处于一致性状态。 隔离性(isolcation) 隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务。 不能被其他事务的操作所千扰,多个并发事务之问要相互隔离。卜 持久性(durability) 持久性是指 一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的。 即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。 事务的隔离级别 事务的隔离级别 多个客户端操作时,各个客户端的事务之间应该是隔离的,相互独立的,不受影响的。 而如果多个事务操作同一批数据时,就会产生不同的问题,我们需要设置不同的隔离级别来解决这些问题。 隔离级别分类 隔离级别 会引发的问题 read uncommitted 读末提交 脏读、不可重复读、幻读 read committed 读已提交 不可重复读、幻读 repeatable read 可重复读 幻读 serializable 串行化 无 引发的问题 问题 现象 脏读 在一个事务处理过程中读取到了另一个未提交事务中的数据,导致2次查询结果不一致 不可重复读 在一个事务处理过程中读取到了另一个事务中修改并已提交的数据,导致2次查询结果不一对我 幻读 查询某数据不存在,准备插入此记录,但执行插入时发现此记录已存在,无法插入.或查询数据不存在执行删除操作,却发现删除成功 事务的隔离级别 查询数据库隔离级别 select @@tx_isolation; 修改数据库隔离级别(需要重新连接) set global transaction isolation level 级别字符串; # 查询事务隔离级别 select @@tx_isolation; # 修改事务隔离级别(修改后需要重新连接) set global transaction isolation level read committed ; 隔离级别问题演示 脏读问题演示 set global transaction isolation level read uncommitted ; start transaction ; update account set money=money-500 where NAME='张三'; update account set money=money+500 where NAME='李四'; # 提交事务 select * from account; rollback ; # 同时开启, 在上一用户transaction执行期间查询, 把transcation未commit的数据读取出来了. start transaction ; select * from account; COMMIT; 解决脏读设置为: set global transaction isolation level read committed ; ...

October 20, 2021&nbsp;·&nbsp;11 分钟&nbsp;·&nbsp;Lizicai