Java反射机制和JDBC

Java反射机制和JDBC

Java反射机制1、反射机制有什么用?

代码语言:javascript代码运行次数:0运行复制通过java语言中的反射机制可以操作字节码文件

可以读和写字节码文件

通过反射机制可以操作代码片段(class文件)2、反射机制相关类在哪个包下

代码语言:javascript代码运行次数:0运行复制java.lang.reflect.*;3、反射机制相关的重要类有哪些?

代码语言:javascript代码运行次数:0运行复制java.lang.Class:代表整个字节码,代表一个类型,整个类

java.lang.reflect.Method:代表字节码中方法字节码,类中方法

java.lang.reflect.Constructor:代表字节码中构造方法字节码,类中构造方法

java.lang.reflect.Field:代表字节码中属性字节码。类中属性三种获取class方法:

第一种代码语言:javascript代码运行次数:0运行复制/*

Class.forName()

1.静态方法

2.参数是一个字符串,且是一个完整的类名

3.完整名必须带有包名。java.lang包不能省略

4.需要处理异常

*/

try{

Class c1 = Class.forName("java,lang.String"); //获取string类型的class字节码

Class c2 = Class.forName("java,util.Date");

Class c3 = Class.forName("java,lang.Integer");

Class c4 = Class.forName("java,lang.System");

} catch (ClassNotFoundException e) {

e.printStackTrace;

}2.第二种

代码语言:javascript代码运行次数:0运行复制// Java中任何一个对象都有一个getClass方法

String s = "abc";

Class x = s.getClass(); // x代表String.class

Date time = new Date();

Class y = time.getClass();3.第三种

代码语言:javascript代码运行次数:0运行复制// java中任何一个类型,包括基本数据类型,都有class属性

Class z = String.class; // z 代表String类型

Class e = int.class; // e 代表int类型

Class b = Date.class; // b 代表Date类型获取到class能干什么?

1.可以实例化对象

代码语言:javascript代码运行次数:0运行复制try {

// 通过反射机制,获取class,可以实例化对象

Class c = Class.forName("re.User"); // c代表user类型

// newInstance() 这个方法会调用User这个类的无参构造方法,完成对象的创建

Object obj = c.newInstance();

System.out.println(obj);

} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {

e.printStackTrace();

}2.实例化对象很灵活

代码语言:javascript代码运行次数:0运行复制public static void main(String[] args) throws Exception {

// 通过io流读取classinfo.properties这个配置文件

FileReader fr = new FileReader("classinfo.properties");

/*

另一种写法,以流的形式返回

InputStream fr = Thread.currentThread()

.getContextClassLoader().getResourceAsStream("classinfo.properties");

*/

// 创建属性类对象map

Properties pro = new Properties();

// 加载

pro.load(fr);

// 关闭流

fr.close();

// 通过key获取value

String className = pro.getProperty("className");

// 通过反射机制实例化对象

Class c = Class.forName(className);

// 实例化对象

Object obj = c.newInstance();

System.out.println(obj);

}如果只希望一个类的静态代码块执行,其他代码一律不执行,就可以使用以下方式

代码语言:javascript代码运行次数:0运行复制public class TestDemo{

public static void main(String[] args) {

try {

// Class.forName()这个方法执行会导致类加载

// 类加载时,静态代码块执行

Class.forName("re.Myclass");

} catch (ClassNotFoundException) {

e.printStackTrace();

}

}

}

class Myclass {

// 静态代码块在类加载时执行,并且只执行一次

static {

System.out.println("MyClass类的静态代码块执行了!");

}

}获取类路径下文件的绝对路径

代码语言:javascript代码运行次数:0运行复制public static void main(String[] args) {

// 前提是此文件必须在src类路径下,才能获取到,起点是src

// 注意获取java文件时需要加.class

/*

解释:Thread.currentThread()获取当前线程对象。

getContextClassLoader()是线程对象的方法,

可以获取到当前线程的类加载器对象。

getResource()【获取资源】这是类加载器对象的方法,

当前线程的类加载器默认从类的根路径下加载资源。

*/

String path = Thread.currentThread().getContextClassLoader()

.getResource("classinfo.properties").getPath();

// 起点是src如:re/User.class

// 这种方式获取绝对路径是通用的

System.out.println(path);

}资源绑定器代码语言:javascript代码运行次数:0运行复制/*

java.util包下提供了一个资源绑定器,便于获取属性配置文件的内容

使用以下方式的时候,属性配饰文件必须是xxx.properties,且必须放到类路径下

*/

public static void main(String[] args) {

// 资源绑定器,这个文件必须是配置文件properties,且在类路径下,参数不能有后缀名

ResourceBundle rb = ResourceBundle.getBundle("classinfo");

String name = rb.getString("className");

System.out.println(name);

}反射属性代码语言:javascript代码运行次数:0运行复制/*测试类*/

package re;

public class Demo {

public String name;

private int age;

protected String sex;

double moeny;

public static final float PI = 3.14f;

}

package re;

import java.lang.reflect.Field;

import java.lang.reflect.Modifier;

/*反射属性测试类*/

public class FieldTest {

public static void main(String[] args) throws Exception {

// 先获取整个类

Class c = Class.forName("re.Demo");

String className = c.getName();

System.out.println("完整类名:" + className);

String simpleName = c.getSimpleName();

System.out.println("简类名:" + simpleName + "\n");

// getFields()此方法,获取类中所有公开属性

Field[] f = c.getFields();

// 获取数组中第0位元素的名字

System.out.println(f[0].getName() + "\n");

// 获取类中所有属性的名字,getDeclaredFields()此方法返回Field数组

Field[] fs = c.getDeclaredFields();

for (Field field : fs) {

// 获取修饰符,getModifiers()返回一个整型,每一个数字对应一个修饰符代号

int i = field.getModifiers();

System.out.print("修饰符代号:" + i + "\t");

// 可以将这一个修饰符代号转换为字符串

System.out.print("对应修饰符名称:" + Modifier.toString(i) + "\t");

// 获取属性类型,getType()方法返回Class

Class fieldtype = field.getType();

// 通过Class可以调用getName,打印属性类型名称

System.out.print("完整类型名:" + fieldtype.getName() + "\t");

System.out.print("简单类型名:" + fieldtype.getSimpleName() + "\t");

// 获取属性名字

System.out.println("属性名:" + field.getName());

}

}

}小案例:反编译类中属性

代码语言:javascript代码运行次数:0运行复制/*测试类*/

package re;

public class Demo {

public String name;

private int age;

protected String sex;

double moeny;

public static final float PI = 3.14f;

}

package re;

import java.lang.reflect.Field;

import java.lang.reflect.Modifier;

/*反编译测试类中属性*/

public class FieldTest01 {

public static void main(String[] args) throws Exception {

Class c = Class.forName("re.Demo");

StringBuilder s = new StringBuilder();

s.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() + " {\n");

Field[] fs = c.getDeclaredFields();

for (Field f : fs) {

s.append("\t" + Modifier.toString(c.getModifiers()) + " " + f.getType().getSimpleName() + " " + f.getName() + ";" + "\n");

}

s.append("}");

System.out.println(s);

}

}

获取和设置属性值代码语言:javascript代码运行次数:0运行复制public class Demo {

public String name;

private int age;

protected String sex;

double moeny;

public static final float PI = 3.14f;

}

// 重点

public static void main(String[] args) throws Exception {

// 通过反射机制给属性赋值和调佣(set和get)

Class c = Class.forName("Demo");

// 创建对象,底层调用了re.Demo类中无参构造方法实现的

Object obj = c.newInstance(); // obj为Demo对象

// getDeclaredField()方法给定参数(属性名),返回一个指定Field

Field f = c.getDeclaredField("name");

// get()方法给定参数(对象)获取Field的值,属性.get(对象)

System.out.println(f.get(obj));

f.set(obj, "张三"); // 设置Demo对象中name属性的值

System.out.println(f.get(obj));

// 设置私有属性的值

Field ageField = c.getDeclaredField("age");

// 打破封装,这种方式会使得私有属性在外部也能访问

ageField.setAccessible(true);

ageField.set(obj, 18);

System.out.println(ageField.get(obj));

}可变长参数代码语言:javascript代码运行次数:0运行复制// 语法:参数为数据类型...参数名

// 1,可变参数要求的是参数0~n个

// 2,最后一个,仅一个

// 例;

public static void main(String[] args) {

a();

a(23,4);

a(1);

b("我","是","中","国","人");

}

public static void a(int...age) {

System.out.println("a方法执行了!");

}

public static void b(String...value) {

// 可变长参数可以作为数组使用

for (String s : value) {

System.out.println(s);

}

}反射方法代码语言:javascript代码运行次数:0运行复制package re;

public class User {

public boolean login(String name, String pwd) {

if ("xc".equals(name) && "123456".equals(pwd)) {

return true;

}

return false;

}

public void out() {

System.out.println("系统退出,谢谢使用!");

}

}

package re;

import java.lang.reflect.Method;

import java.lang.reflect.Modifier;

public class MethodTest {

public static void main(String[] args) throws Exception {

Class c = Class.forName("re.User");

// 获取所有的方法(包括私有)

Method[] me = c.getDeclaredMethods();

for (Method method : me) {

// 获取访问修饰符

System.out.print(Modifier.toString(method.getModifiers()) + "\t");

// 获取返回值类型

System.out.print(method.getReturnType().getSimpleName() + "\t");

// 获取方法名

System.out.println(method.getName());

// 获取方法参数数据类型列表

Class[] type = method.getParameterTypes();

for (Class aClass : type) {

System.out.println(aClass.getSimpleName());

}

}

}

}反编译方法签名

代码语言:javascript代码运行次数:0运行复制package re;

public class User {

public boolean login(String name, String pwd) {

if ("xc".equals(name) && "123456".equals(pwd)) {

return true;

}

return false;

}

public void out() {

System.out.println("系统退出,谢谢使用!");

}

}

package re;

import java.lang.reflect.Method;

import java.lang.reflect.Modifier;

public class Demo2 {

public static void main(String[] args) throws Exception {

Class c = Class.forName("re.User");

StringBuilder sb = new StringBuilder();

sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName()+ " {\n");

Method[] md = c.getDeclaredMethods();

for (Method method : md) {

sb.append("\t");

sb.append(Modifier.toString(method.getModifiers()));

sb.append(" ");

sb.append(method.getReturnType().getSimpleName());

sb.append(" ");

sb.append(method.getName());

sb.append("(");

Class[] cs = method.getParameterTypes();

for (Class aClass : cs) {

sb.append(aClass.getSimpleName() + " ,");

}

if (cs.length != 0) {

// 删除指定下标上的字符

sb.deleteCharAt(sb.length() - 1);

}

sb.append(")");

sb.append("\n");

}

sb.append("}");

System.out.println(sb);

}

}

通过反射机制调用方法代码语言:javascript代码运行次数:0运行复制package re;

import java.lang.reflect.Method;

// 重点

public class MethodTest2 {

public static void main(String[] args) throws Exception {

// 不使用反射机制调用方法

// 创建对象

User user = new User();

// 调用方法

boolean flag = user.login("xc", "123456");

System.out.println(flag ? "登陆成功" : "登录失败");

// 使用反射机制调用方法

Class c = Class.forName("re.User");

Object obj = c.newInstance();

// 获取Method

Method loginMethod = c.getDeclaredMethod("login", String.class, String.class);

// 调用方法

Object retrunValue = loginMethod.invoke(obj, "xc", "123");

// 强制转换类型

boolean flag2 = (Boolean) retrunValue;

System.out.println(flag2 ? "登陆成功" : "登录失败");

}

}反编译构造方法代码语言:javascript代码运行次数:0运行复制package re;

/*测试类*/

public class Vip {

int no;

int age;

String name;

String birthday;

public Vip(int no) {

this.no = no;

}

public Vip(int no, int age) {

this.no = no;

this.age = age;

}

public Vip(int no, int age, String name) {

this.no = no;

this.age = age;

this.name = name;

}

public Vip(int no, int age, String name, String birthday) {

this.no = no;

this.age = age;

this.name = name;

this.birthday = birthday;

}

}

package re;

import java.lang.reflect.Constructor;

import java.lang.reflect.Field;

import java.lang.reflect.Modifier;

/*反编译构造方法*/

public class ConstructorTest {

public static void main(String[] args) throws Exception {

// 创建StringBuilder

StringBuilder sb = new StringBuilder();

// 获取Class

Class c = Class.forName("re.Vip");

// 获取修饰符列表

sb.append(Modifier.toString(c.getModifiers()));

sb.append(" class ");

// 获取简类名

sb.append(c.getSimpleName());

sb.append(" {\n");

// 获取属性(数组)

Field[] fd = c.getDeclaredFields();

for (Field field : fd) {

// 通过for循环遍历属性数组,获取属性数据类型,属性名

sb.append("\t" + field.getType().getSimpleName() + " " + field.getName() + ";\n");

}

sb.append("\n");

// 获取构造方法(数组)

Constructor[] cons = c.getDeclaredConstructors();

for (Constructor constructor : cons) {

sb.append("\t");

// 遍历数组获取修饰符列表,简答类名

sb.append(Modifier.toString(c.getModifiers()));

sb.append(" " + c.getSimpleName() + "(");

// 获取参数数据类型列表

Class[] par = constructor.getParameterTypes();

for (Class aClass : par) {

// 获取参数数据类型简名

sb.append(aClass.getSimpleName() + ",");

}

// 判断如果数组的长度不为零,就删除逗号

if (par.length != 0) {

sb.deleteCharAt(sb.length() - 1);

}

sb.append(") {}\n");

}

sb.append("}");

// 打印输出

System.out.println(sb);

}}

}

调用构造方法代码语言:javascript代码运行次数:0运行复制package re;

/*测试类*/

public class Vip {

int no;

int age;

String name;

String birthday;

public Vip(){}

public Vip(int no) {

this.no = no;

}

public Vip(int no, int age) {

this.no = no;

this.age = age;

}

public Vip(int no, int age, String name) {

this.no = no;

this.age = age;

this.name = name;

}

public Vip(int no, int age, String name, String birthday) {

this.no = no;

this.age = age;

this.name = name;

this.birthday = birthday;

}

@Override

public String toString() {

return "Vip{" +

"no=" + no +

", age=" + age +

", name='" + name + '\'' +

", birthday='" + birthday + '\'' +

'}';

}

}

package re;

import java.lang.reflect.Constructor;

/*调用构造方法实例化对象*/

public class ConstructorTest1 {

public static void main(String[] args) throws Exception {

// 不使用反射机制调用构造方法

Vip vip = new Vip();

Vip vip1 = new Vip(110,24,"xc", "2002-10-15");

System.out.println(vip1);

// 使用反射机制调用构造方法

Class c = Class.forName("re.Vip");

// 调用无参数构造方法

Object obj = c.newInstance();

System.out.println(obj);

// 调用有参数构造方法

// 第一步,获取要调用的构造方法

Constructor con = c.getDeclaredConstructor(int.class, int.class, String.class, String.class);

// 调用有参构造方法,创建对象

Object newobj = con.newInstance(110,24,"xc", "2002-10-15");

System.out.println(newobj);

// 调用无参数构造方法

Constructor con2 = c.getDeclaredConstructor();

// 调用无参构造方法,创建对象

Object newobj2 = con.newInstance();

System.out.println(newobj2);

}

}获取父类和父接口代码语言:javascript代码运行次数:0运行复制public static void main(String[] args) throws Exception {

// 获取父类和父接口

// String举例

Class c = Class.forName("java.lang.String");

// 获取String的父类

Class supers = c.getSuperclass();

System.out.println(supers.getName());

// 获取接口

Class[] interfaces = c.getInterfaces();

for (Class in : interfaces) {

System.out.println(in.getName());

}

}注解注解,也称作注释,英文单词Annotation

注解也是一种引用数据类型,编译之后也会生成xxx.class文件

怎么自定义注解?语法格式?

注解使用场景

jdk内置了哪些注解

@Override标志性注解

元注解

Deprecated,已过时,在调用的时候会出现横线,用于向其他程序员传递一个信息

注解中定义属性代码语言:javascript代码运行次数:0运行复制package at;

/*

自定义注解:MyAnnotation

* */

public @interface MyAnnotation {

/*

* 通常在注解中可以定义属性,以下为MyAnnotation中的内部属性

* 非常像方法

* */

String name();

// 给属性指定默认值

int age() default 18;

// 邮箱属性

String[] emil();

}

package at;

public class AnnotationTest {

// 在使用时,如果一个注解中有属性,必须给属性赋值

// 除非有默认值,则可以不写

// 属性数组中只有一个元素时可以省略大括号

@MyAnnotation(name = "zhangsan", emil = "fx@outlook.com")

public AnnotationTest() {}

// 属性数组有多个元素,则不能省略大括号

@MyAnnotation(name = "zhangsan", emil = {"fx@outlook.com", "45@123.com"})

public AnnotationTest() {}

}关于属性名为value时省略问题:

如果一个注解中只有一个属性名为value,那么可以省略,如果有多个属性,则不能省略

注解中的属性类型可以是:

byte,short,int,long。float,double。boolean,char,String,Class,枚举类型

以及上述每一种的数组形式

反射注解获取类上的注解

代码语言:javascript代码运行次数:0运行复制package at;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

/*

自定义注解:MyAnnotation

* */

@Retention(RetentionPolicy.RUNTIME)

public @interface MyAnnotation {

/*

* 通常在注解中可以定义属性,以下为MyAnnotation中的内部属性

* 非常像方法

* */

String name();

// 给属性指定默认值

int age() default 18;

String value();

}

package at;

/*注解*/

@MyAnnotation(name = "lisi", value = "12")

public class AnnotationTest {

// 在使用时,如果一个注解中有属性,必须给属性赋值

@MyAnnotation(name = "zhangsan", value = "12")

public AnnotationTest() {}

}

package at;

/*通过反射机制获取到注解的值*/

public class Test {

public static void main(String[] args) throws Exception {

Class c = Class.forName("at.AnnotationTest");

// 判断这个类中是否有MyAnnotation注解

if (c.isAnnotationPresent(MyAnnotation.class)) {

// 如果有则可以获取到注解对象

MyAnnotation m = (MyAnnotation) c.getAnnotation(MyAnnotation.class);

// 获取到注解对象则可以获取到值,如果不是value则可以点到其他属性

String name = m.value();

System.out.println(name);

String name1 = m.name();

System.out.println(name1);

}

}

}获取方法上的注解

代码语言:javascript代码运行次数:0运行复制package at;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface Ma {

String user();

String password();

}

package at;

import java.lang.reflect.Method;

public class Test1 {

@Ma(user = "xc",password = "123")

public void todo() {}

public static void main(String[] args) throws Exception {

Class c = Class.forName("at.Test1");

Method m = c.getDeclaredMethod("todo");

if (m.isAnnotationPresent(Ma.class)) {

Ma ma = m.getAnnotation(Ma.class);

System.out.println(ma.user());

System.out.println(ma.password());

}

}

}JDBC使用Java链接数据库六步曲(非常重要)

注册驱动(作用:告诉Java程序,即将要连接的数据库是哪个品牌的数据库)获取连接(表示JVM的进程和数据库进程之间的通道打开了,属于进程之间的通信,使用后要关闭对象)获取数据库操作对象(专门执行SQL语句的对象)执行SQL语句(DQL,DML)处理查询结果集(只有当第四步执行的是select的语句的时候,才有第五步的查询结果集)释放资源(使用完资源之后一定要关闭资源)代码语言:javascript代码运行次数:0运行复制package day1;

import com.mysql.cj.jdbc.Driver;

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.SQLException;

import java.sql.Statement;

/*

* JDBC编程六部曲

* */

public class JdbcTest01 {

public static void main(String[] args) {

Statement smt = null;

Connection connection = null;

try {

// 1.注册驱动

DriverManager.registerDriver(new Driver());

// 2.获取连接

// 加在库名后面“?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false”

String url = "jdbc:mysql://localhost:3306/testdb";

String user = "root";

String password = "xcfx";

connection = DriverManager.getConnection(url,user,password);

// com.mysql.cj.jdbc.ConnectionImpl@34a3d150

System.out.println("数据库对象:" + connection);

// 3.获取数据库操作对象(Statement专门执行SQL语句的)

smt = connection.createStatement();

// 4.执行SQL语句

String sql2 = "update employee set Salary = 5000 where Name = '张三'";

String sql = "insert into employee values(default,'女','黑马',2000,'2000-5-3',1)";

// 此语句专门执行DML语句(insert delete update)

// 返回受影响的行数

int count = smt.executeUpdate(sql2);

System.out.println(count == 1 ? "操作成功" : "操作失败");

} catch (SQLException e) {

e.printStackTrace();

} finally {

// 6.关闭资源

// 要遵循从小到大依次关闭

if (smt != null) {

try {

smt.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if (connection != null) {

try {

connection.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

}

}

}

代码语言:javascript代码运行次数:0运行复制public static void main(String[] args) {

try {

// 第二种方式注册驱动,通过反射机制导致类加载

Class.forName("com.mysql.cj.jdbc.Driver");

Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/testdb", "root", "xcfx");

System.out.println(conn);

} catch (ClassNotFoundException | SQLException e) {

e.printStackTrace();

}

}通过配置文件方式获取数据库信息

代码语言:javascript代码运行次数:0运行复制package day1;

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.SQLException;

import java.sql.Statement;

import java.util.ResourceBundle;

public class JdbcTest03 {

public static void main(String[] args) {

// 资源绑定器

ResourceBundle bundle = ResourceBundle.getBundle("day1/configbase");

String driver = bundle.getString("driver");

String url = bundle.getString("url");

String user = bundle.getString("user");

String password = bundle.getString("password");

Connection conn = null;

Statement smtt = null;

try {

Class.forName(driver);

conn = DriverManager.getConnection(url,user,password);

smtt = conn.createStatement();

String sql = "update employee set Salary = 5000 where Name = '张三'";

int count = smtt.executeUpdate(sql);

System.out.println(count == 1 ? "操作成功" : "操作失败");

} catch (ClassNotFoundException | SQLException e) {

e.printStackTrace();

} finally {

if (smtt != null) {

try {

smtt.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if (conn != null) {

try {

conn.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

}

}

}

配置文件

代码语言:javascript代码运行次数:0运行复制driver=com.mysql.cj.jdbc.Driver

url=jdbc:mysql://localhost:3306/testdb

user=root

password=xcfx处理查询结果集(遍历结果集)代码语言:javascript代码运行次数:0运行复制package day1;

import java.sql.*;

// 处理查询结果集(遍历结果集)

public class JdbcTest04 {

public static void main(String[] args) {

Connection sc = null; // 连接对象

Statement smt = null; // 操作对象

ResultSet re = null; // 结果集

try {

// 1.注册驱动

Class.forName("com.mysql.cj.jdbc.Driver");

// 2.获取连接

sc = DriverManager.getConnection("jdbc:mysql://localhost:3306/testdb","root","xcfx");

// 3.获取数据库操作对象

smt = sc.createStatement();

// 4.执行SQL语句

String sql = "select * from employee";

// int executeUpdate(insert/update/delete)

// Resultset executeQuery(select)

re = smt.executeQuery(sql); // executeQuery专门执行dql语句的方法,返回单个resultset对象

// 5.处理查询结果集

while (re.next()) {

// getString方法可以以列表下表获取,也可以以列的名字获取

// 如果列有别名,则按照别名获取

// 除getstring以string类型取出数据外,还可以以其他类型取出数据

// 好处是可以直接做数学运算

int n1 = re.getInt(1);

String n2 = re.getString(2);

String n3 = re.getString("gender");

String n4 = re.getString("salary");

String n5 = re.getString("birthday");

String n6 = re.getString("starid");

System.out.println((n1 + 1) + "\t" + n2 + "\t" + n3 + "\t" + n4 + "\t" + n5 + "\t" + n6);

}

} catch (Exception e) {

e.printStackTrace();

} finally {

// 6.释放资源(从小到大)

if (re != null) {

try {

re.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if (smt != null) {

try {

smt.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if (sc != null) {

try {

sc.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

}

}

}

模拟用户登录代码语言:javascript代码运行次数:0运行复制package day1;

import java.sql.*;

import java.util.HashMap;

import java.util.Map;

import java.util.Scanner;

public class JdbcTest05 {

public static void main(String[] args) {

// 界面初始化

Map ui = intoUI();

// 验证用户名和密码

boolean loginSuccess = login(ui);

// 最后输出结果

System.out.println(loginSuccess ? "登陆成功" : "登录失败");

}

/**

* 用户登录

* @param ui 用户登录信息

* @return false表示失败,true表示成功

*/

private static boolean login(Map ui) {

// JDBC代码

Connection conn = null;

Statement smt = null;

ResultSet re = null;

// 表示

boolean flag = false;

try {

// 1.注册驱动

Class.forName("com.mysql.cj.jdbc.Driver");

// 2.获取连接

conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","xcfx");

// 3.获取数据库操作对象

smt = conn.createStatement();

// 4.执行SQL语句

String sql = "select * from t_user where user = '"+ui.get("userName")+"' and pwd = '"+ui.get("pwd")+"'";

re = smt.executeQuery(sql);

// 5.处理查询结果集

if (re.next()) {

flag = true;

}

} catch (Exception e) {

e.printStackTrace();

} finally {

// 6.释放资源

if (re != null) {

try {

re.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if (smt != null) {

try {

smt.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if (conn != null) {

try {

conn.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

}

return flag;

}

/**

* 初始化界面

* @return 用户输入的用户名或密码的信息

*/

private static Map intoUI() {

Scanner sc = new Scanner(System.in);

System.out.print("用户名:");

String userName = sc.next();

System.out.print("密码:");

String pwd = sc.next();

Map userlogin = new HashMap();

userlogin.put("userName",userName);

userlogin.put("pwd",pwd);

return userlogin;

}

}

上述代码存在SQL注入问题例:用户名:fa

密码:fa’or’1’=’1

登陆成功如果上述SQL中包含关键字,那么此处已经完成了SQL语句的拼接,此时SQL会发送给DBMS,DBMS会进行SQL编译

解决SQL注入问题只要用户提供的信息不参与SQL语句的编译过程,问题就解决了

即使用户提供的信息中包含有SQL语句的关键字,但是没有参与编译,也不起作用

若想用户信息不参与SQL语句编译,那么必须使用java.sql.PreparedStatement

PreparedStatement接口继承了java.sql.Statement

PreparedStatement是属于预编译的数据库操作对象

PreparedStatement原理是:预先对SQL语句的框架进行编译,然后再给SQL语句传”值”

代码语言:javascript代码运行次数:0运行复制package day1;

import java.sql.*;

import java.util.HashMap;

import java.util.Map;

import java.util.Scanner;

/**

* 解决SQL注入问题

* 只要用户提供的信息不参与SQL语句的编译过程,问题就解决了

* 即使用户提供的信息中包含有SQL语句的关键字,但是没有参与编译,也不起作用

* 若想用户信息不参与SQL语句编译,那么必须使用java.sql.PreparedStatement

* PreparedStatement接口继承了java.sql.Statement

* PreparedStatement是属于预编译的数据库操作对象

* PreparedStatement原理是:预先对SQL语句的框架进行编译,然后再给SQL语句传"值"

*/

public class JdbcTest06 {

public static void main(String[] args) {

// 界面初始化

Map ui = intoUI();

// 验证用户名和密码

boolean loginSuccess = login(ui);

// 最后输出结果

System.out.println(loginSuccess ? "登陆成功" : "登录失败");

}

/**

* 用户登录

* @param ui 用户登录信息

* @return false表示失败,true表示成功

*/

private static boolean login(Map ui) {

// JDBC代码

Connection conn = null;

PreparedStatement ps = null; // 这里使用PreparedStatement(预编译数据库操作对象)

ResultSet re = null;

// 表示

boolean flag = false;

try {

// 1.注册驱动

Class.forName("com.mysql.cj.jdbc.Driver");

// 2.获取连接

conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","xcfx");

// 3.获取预编译的数据库操作对象

// 这是SQL语句的框子(框架)一个?代表一个占位符,一个?接收一个值,?不能使用单引号括起来

String sql = "select * from t_user where user = ? and pwd = ?";

ps = conn.prepareStatement(sql);

// 给占位符?传值JDBC中所有下表都从1开始

ps.setString(1, ui.get("userName"));

ps.setString(2, ui.get("pwd"));

// 4.执行SQL语句

re = ps.executeQuery();

// 5.处理查询结果集

if (re.next()) {

flag = true;

}

} catch (Exception e) {

e.printStackTrace();

} finally {

// 6.释放资源

if (re != null) {

try {

re.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if (ps != null) {

try {

ps.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if (conn != null) {

try {

conn.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

}

return flag;

}

/**

* 初始化界面

* @return 用户输入的用户名或密码的信息

*/

private static Map intoUI() {

Scanner sc = new Scanner(System.in);

System.out.print("用户名:");

String userName = sc.next();

System.out.print("密码:");

String pwd = sc.next();

Map userlogin = new HashMap();

userlogin.put("userName",userName);

userlogin.put("pwd",pwd);

return userlogin;

}

}

Statement和PreparedStatement对比Statement存在SQL注入问题Statement编译一次执行一次,PreparedStatement编译一次执行n次,效率略高PreparedStatement会在编译阶段做类型安全检查什么时候用Statement?项目支持SQL注入或需要进行SQL语句拼接的情况下,必须使用StatementStatement用法示例代码语言:javascript代码运行次数:0运行复制package day1;

import java.sql.*;

import java.util.Scanner;

public class JdbcTset07 {

public static void main(String[] args) {

// 模拟用户升序和降序

Scanner sc = new Scanner(System.in);

System.out.println("请输入desc/asc,desc表示升序,asc表示降序");

System.out.print("请输入:");

String keywords = sc.next();

// JDBC编程六步

Connection conn = null;

Statement smt = null;

ResultSet re = null;

try {

// 注册驱动

Class.forName("com.mysql.cj.jdbc.Driver");

// 获取连接

conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","xcfx");

// 获取数据库操作对象

smt = conn.createStatement();

// 执行SQL

String sql = "select * from t_user order by id " + keywords;

re = smt.executeQuery(sql);

// 遍历结果集

while (re.next()) {

System.out.println(re.getString("user") + "\t" + re.getString("pwd"));

}

} catch (Exception e) {

e.printStackTrace();

} finally {

// 释放资源

if (re != null) {

try {

re.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if (smt != null) {

try {

smt.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if (conn != null) {

try {

conn.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

}

}

}

PreparedStatement完成增删改代码语言:javascript代码运行次数:0运行复制package day1;

import java.sql.*;

// PreparedStatement完成增删改

public class JdbcTest08 {

public static void main(String[] args) {

Connection conn = null;

PreparedStatement ps = null;

try {

// 注册驱动

Class.forName("com.mysql.cj.jdbc.Driver");

// 获取连接

conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","xcfx");

// 获取预编译数据库操作对象

String sql = "insert into t_user values(default,?,?)";

ps = conn.prepareStatement(sql);

ps.setString(1,"jack");

ps.setString(2,"hello");

// 执行SQL

int count = ps.executeUpdate();

System.out.println(count);

} catch (Exception e) {

e.printStackTrace();

} finally {

// 关闭资源

if (ps != null) {

try {

ps.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if (conn != null) {

try {

conn.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

}

}

}

JDBC事务机制1,JDBC中的事务是自动提交的,什么是自动提交?

代码语言:javascript代码运行次数:0运行复制只要执行任意一条SQL语句,则自动提交一次。这是JDBC默认的事务行为

但是在实际的业务中,通常都是n条DML语句共同联合才能完成的,

必须保证这些DML语句在同一个事务中同时成功或同时失败2,以下程序先验证JDBC事务是否是自动提交机制

代码语言:javascript代码运行次数:0运行复制结论,Jdbc中只要执行任意一条DML语句,就提交一次代码语言:javascript代码运行次数:0运行复制/-----JDB代码省略

// 获取预编译数据库操作对象

String sql = "update t_user set pwd=? where id=?";

ps = conn.prepareStatement(sql);

ps.setString(1,"jack");

ps.setInt(2,3); // 修改id为3的密码

// 执行SQL

int count = ps.executeUpdate();

System.out.println(count);

// 重新给占位符传值

ps = conn.prepareStatement(sql);

ps.setString(1,"meke");

ps.setInt(2,1); // 修改id为2的密码

count = ps.executeUpdate();

System.out.println(count);模拟银行账户转账

代码语言:javascript代码运行次数:0运行复制package day1;

import java.sql.*;

/**

* 本节点重点,

* 将自动提交机制修改为手动提交

* conn.setAutoCommit(false); 开启事务

*

* 如果程序能运行到这里说明上述代码没有异常,事务结束,手动提交

* conn.commit(); 提交事务

*

* if (conn != null) {

* try {

* // 回滚事务

* conn.rollback();

* } catch (SQLException ex) {

* ex.printStackTrace();

* }

* }

*/

public class JdbcTest10 {

public static void main(String[] args) {

Connection conn = null;

PreparedStatement ps = null;

try {

// 注册驱动

Class.forName("com.mysql.cj.jdbc.Driver");

// 获取连接

conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","xcfx");

// 将自动提交机制修改为手动提交

conn.setAutoCommit(false); // 开启事务

// 获取预编译数据库操作对象

String sql = "update t_act set balance=? where actno=?";

ps = conn.prepareStatement(sql);

// 给?传值

ps.setDouble(1,10000);

ps.setInt(2,111);

int count = ps.executeUpdate(); // 执行SQL语句

// 此时再出现异常,则不会自动提交

// String s = null;

// s.toString();

// 再次修改

ps.setDouble(1,10000);

ps.setDouble(2,222);

count += ps.executeUpdate(); // 再次执行SQL语句

System.out.println(count == 2 ? "转账成功" : "转账失败");

// 如果程序能运行到这里说明上述代码没有异常,事务结束,手动提交

conn.commit(); // 提交事务

} catch (Exception e) {

if (conn != null) {

try {

// 回滚事务

conn.rollback();

} catch (SQLException ex) {

ex.printStackTrace();

}

}

e.printStackTrace();

} finally {

// 关闭资源

if (ps != null) {

try {

ps.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if (conn != null) {

try {

conn.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

}

}

}

表t_act

代码语言:javascript代码运行次数:0运行复制DROP TABLE IF EXISTS `t_act`;

CREATE TABLE `t_act` (

`actno` int NULL DEFAULT NULL,

`balance` double(8, 2) NULL DEFAULT NULL

)

INSERT INTO `t_act` VALUES (111, 20000.00);

INSERT INTO `t_act` VALUES (222, 0.00);实现模糊查询工具类

代码语言:javascript代码运行次数:0运行复制package util;

import java.sql.*;

// JDBC工具类

public class JDBCutil {

/**

* 工具类中的构造方法一般都是私有的

* 因为工具类中的方法都是静态的,不需要new对象,直接采用类名调用

*/

private JDBCutil() {}

// 静态代码块在类加载时执行,且执行一次

static {

try {

Class.forName("com.mysql.cj.jdbc.Driver");

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

}

/**

* 获取数据库连接对象

* @return 返回连接对象

* @throws SQLException

*/

public static Connection getConnection() throws SQLException {

return DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","xcfx");

}

/**

* 关闭资源

* @param conn 连接对象

* @param ps 数据库操作对象

* @param rs 结果集对象

*/

public static void close(Connection conn, Statement ps, ResultSet rs) {

if (rs != null) {

try {

rs.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if (ps != null) {

try {

ps.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if (conn != null) {

try {

conn.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

}

}

测试类

代码语言:javascript代码运行次数:0运行复制package day1;

import util.JDBCutil;

import java.sql.*;

/**

* 这个程序有两个任务

* 1.测试JDBCutil工具类是否好用

* 2.实现模糊查询

*/

public class JdbcTest11 {

public static void main(String[] args) {

Connection conn = null;

PreparedStatement ps = null;

ResultSet rs = null;

try {

// 获取连接

conn = JDBCutil.getConnection();

// 获取预编译的数据库操作对象

String sql = "select * from t_user where user like ?";

ps = conn.prepareStatement(sql); // 编译SQL语句

ps.setString(1,"%x%"); // 给?传值

rs = ps.executeQuery(); // 执行SQL语句,返回结果集

// 遍历结果集

while (rs.next()) {

System.out.println(rs.getString("user") + "\t" + rs.getString("pwd"));

}

} catch (Exception e) {

e.printStackTrace();

} finally {

// 释放资源

JDBCutil.close(conn,ps,rs);

}

}

}

行级锁在SQL语句select后加上for update,此数据就会锁住,其他事物不可修改