Java反射机制 1、反射机制有什么用?
通过java语言中的反射机制可以操作字节码文件
可以读和写字节码文件
通过反射机制可以操作代码片段(class文件)
2、反射机制相关类在哪个包下
java.lang.reflect.*;
3、反射机制相关的重要类有哪些?
java.lang.Class:代表整个字节码,代表一个类型,整个类
java.lang.reflect.Method:代表字节码中方法字节码,类中方法
java.lang.reflect.Constructor:代表字节码中构造方法字节码,类中构造方法
java.lang.reflect.Field:代表字节码中属性字节码。类中属性
三种获取class方法:
第一种 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 try { Class c1 = Class.forName("java,lang.String" ); 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.第二种
1 2 3 4 5 6 String s = "abc" ;Class x = s.getClass(); Date time = new Date ();Class y = time.getClass();
3.第三种
1 2 3 4 Class z = String.class; Class e = int .class; Class b = Date.class;
获取到class能干什么?
1.可以实例化对象
1 2 3 4 5 6 7 8 9 10 11 try { Class c = Class.forName("re.User" ); Object obj = c.newInstance(); System.out.println(obj); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { e.printStackTrace(); }
2.实例化对象很灵活
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public static void main (String[] args) throws Exception { FileReader fr = new FileReader ("classinfo.properties" ); Properties pro = new Properties (); pro.load(fr); fr.close(); String className = pro.getProperty("className" ); Class c = Class.forName(className); Object obj = c.newInstance(); System.out.println(obj); }
如果只希望一个类的静态代码块执行,其他代码一律不执行,就可以使用以下方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class TestDemo { public static void main (String[] args) { try { Class.forName("re.Myclass" ); } catch (ClassNotFoundException) { e.printStackTrace(); } } } class Myclass { static { System.out.println("MyClass类的静态代码块执行了!" ); } }
获取类路径下文件的绝对路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public static void main (String[] args) { String path = Thread.currentThread().getContextClassLoader() .getResource("classinfo.properties" ).getPath(); System.out.println(path); }
资源绑定器 1 2 3 4 5 6 7 8 9 10 11 public static void main (String[] args) { ResourceBundle rb = ResourceBundle.getBundle("classinfo" ); String name = rb.getString("className" ); System.out.println(name); }
反射属性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 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" ); Field[] f = c.getFields(); System.out.println(f[0 ].getName() + "\n" ); Field[] fs = c.getDeclaredFields(); for (Field field : fs) { int i = field.getModifiers(); System.out.print("修饰符代号:" + i + "\t" ); System.out.print("对应修饰符名称:" + Modifier.toString(i) + "\t" ); Class fieldtype = field.getType(); System.out.print("完整类型名:" + fieldtype.getName() + "\t" ); System.out.print("简单类型名:" + fieldtype.getSimpleName() + "\t" ); System.out.println("属性名:" + field.getName()); } } }
小案例:反编译类中属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 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); } }
获取和设置属性值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 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 { Class c = Class.forName("Demo" ); Object obj = c.newInstance(); Field f = c.getDeclaredField("name" ); System.out.println(f.get(obj)); f.set(obj, "张三" ); System.out.println(f.get(obj)); Field ageField = c.getDeclaredField("age" ); ageField.setAccessible(true ); ageField.set(obj, 18 ); System.out.println(ageField.get(obj)); }
可变长参数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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); } }
反射方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 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()); } } } }
反编译方法签名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 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); } }
通过反射机制调用方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 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 loginMethod = c.getDeclaredMethod("login" , String.class, String.class); Object retrunValue = loginMethod.invoke(obj, "xc" , "123" ); boolean flag2 = (Boolean) retrunValue; System.out.println(flag2 ? "登陆成功" : "登录失败" ); } }
反编译构造方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 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 sb = new StringBuilder (); 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) { 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); }} }
调用构造方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 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); } }
获取父类和父接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public static void main (String[] args) throws Exception { Class c = Class.forName("java.lang.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文件
怎么自定义注解?语法格式?
[修饰符列表] @interface 注解类型名 {}
注解使用场景
1,注解使用时的语法格式是:@注解类型名
2,注解可以出现在类上,属性上,方法上,变量上等等…
3,注解还可以出现在注解类型上
jdk内置了哪些注解
Annotation Type Annotation Type 已过时的 注释@Deprecated的程序元素是程序员不鼓励使用的程序元素,通常是因为它是危险的,或者因为存在更好的替代方法。 FunctionalInterface 使用的信息注释类型,以指示在接口类型声明旨在是一个 功能接口由Java语言规范所定义的。 Override 表示方法声明旨在覆盖超类型中的方法声明。 SafeVarargs 程序员断言注释方法或构造函数的正文不会对其varargs参数执行潜在的不安全操作。 SuppressWarnings 表示在注释元素(以及注释元素中包含的所有程序元素)中应该抑制命名的编译器警告。
@Override标志性注解
@Override注解只能用在方法,
@Override这个注解是给编译器参考的,和运行阶段没有关系
凡是Java中的方法有这个注解的,编译器都会进行编译检查,如果这个方法
不是重写父类中的方法,编译器会编译时错误
元注解
解释:用来标注“注解类型”的“注解”,被称为元注解
常见的元注解:Target,Retention
关于Target注解
这是一个元注解,用来标注“注解类型”的“注解”
target注解用来标注“被标注的注解”可以出现在哪些位置上
@Target(ElementType.METHOD):表示“被标注的注解”只能用在方法上
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE})
表示可以出现在,构造方法,属性,局部变量,方法,包,模块,参数,类上
关于Retention注解
这是一个元注解,用来标注“注解类型”的“注解”
Retention注解用来标注“被标注的注解”最终保存到哪
@Retention(RetentionPolicy.SOURCE):表示该注解只保留在java源文件中
@Retention(RetentionPolicy.CLASS):表示该注解被保存在class文件中
@Retention(RetentionPolicy.RUNTIME):表示该注解被保存在class文件中,并且可以被反射机制读取
Deprecated,已过时,在调用的时候会出现横线,用于向其他程序员传递一个信息
注解中定义属性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package at;public @interface 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,枚举类型
以及上述每一种的数组形式
反射注解 获取类上的注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 package at;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;@Retention(RetentionPolicy.RUNTIME) public @interface 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" ); if (c.isAnnotationPresent(MyAnnotation.class)) { MyAnnotation m = (MyAnnotation) c.getAnnotation(MyAnnotation.class); String name = m.value(); System.out.println(name); String name1 = m.name(); System.out.println(name1); } } }
获取方法上的注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 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的语句的时候,才有第五步的查询结果集) 释放资源(使用完资源之后一定要关闭资源) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 package day1;import com.mysql.cj.jdbc.Driver;import java.sql.Connection;import java.sql.DriverManager;import java.sql.SQLException;import java.sql.Statement;public class JdbcTest01 { public static void main (String[] args) { Statement smt = null ; Connection connection = null ; try { DriverManager.registerDriver(new Driver ()); String url = "jdbc:mysql://localhost:3306/testdb" ; String user = "root" ; String password = "xcfx" ; connection = DriverManager.getConnection(url,user,password); System.out.println("数据库对象:" + connection); smt = connection.createStatement(); String sql2 = "update employee set Salary = 5000 where Name = '张三'" ; String sql = "insert into employee values(default,'女','黑马',2000,'2000-5-3',1)" ; int count = smt.executeUpdate(sql2); System.out.println(count == 1 ? "操作成功" : "操作失败" ); } catch (SQLException e) { e.printStackTrace(); } finally { if (smt != null ) { try { smt.close(); } catch (SQLException e) { e.printStackTrace(); } } if (connection != null ) { try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
1 2 3 4 5 6 7 8 9 10 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(); } }
通过配置文件方式获取数据库信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 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(); } } } } }
配置文件
1 2 3 4 driver =com.mysql.cj.jdbc.Driver url =jdbc:mysql://localhost:3306/testdb user =root password =xcfx
处理查询结果集(遍历结果集) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 package day1;import java.sql.*;public class JdbcTest04 { public static void main (String[] args) { Connection sc = null ; Statement smt = null ; ResultSet re = null ; try { Class.forName("com.mysql.cj.jdbc.Driver" ); sc = DriverManager.getConnection("jdbc:mysql://localhost:3306/testdb" ,"root" ,"xcfx" ); smt = sc.createStatement(); String sql = "select * from employee" ; re = smt.executeQuery(sql); while (re.next()) { 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 { 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(); } } } } }
模拟用户登录 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 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<String,String> ui = intoUI(); boolean loginSuccess = login(ui); System.out.println(loginSuccess ? "登陆成功" : "登录失败" ); } private static boolean login (Map<String, String> ui) { Connection conn = null ; Statement smt = null ; ResultSet re = null ; boolean flag = false ; try { Class.forName("com.mysql.cj.jdbc.Driver" ); conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test" ,"root" ,"xcfx" ); smt = conn.createStatement(); String sql = "select * from t_user where user = '" +ui.get("userName" )+"' and pwd = '" +ui.get("pwd" )+"'" ; re = smt.executeQuery(sql); if (re.next()) { flag = true ; } } 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(); } } } return flag; } private static Map<String, String> intoUI () { Scanner sc = new Scanner (System.in); System.out.print("用户名:" ); String userName = sc.next(); System.out.print("密码:" ); String pwd = sc.next(); Map<String,String> userlogin = new HashMap <String,String>(); userlogin.put("userName" ,userName); userlogin.put("pwd" ,pwd); return userlogin; } }
如果上述SQL中包含关键字,那么此处已经完成了SQL语句的拼接,此时SQL会发送给DBMS,DBMS会进行SQL编译
解决SQL注入问题 只要用户提供的信息不参与SQL语句的编译过程,问题就解决了
即使用户提供的信息中包含有SQL语句的关键字,但是没有参与编译,也不起作用
若想用户信息不参与SQL语句编译,那么必须使用java.sql.PreparedStatement
PreparedStatement接口继承了java.sql.Statement
PreparedStatement是属于预编译的数据库操作对象
PreparedStatement原理是:预先对SQL语句的框架进行编译,然后再给SQL语句传”值”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 package day1;import java.sql.*;import java.util.HashMap;import java.util.Map;import java.util.Scanner;public class JdbcTest06 { public static void main (String[] args) { Map<String,String> ui = intoUI(); boolean loginSuccess = login(ui); System.out.println(loginSuccess ? "登陆成功" : "登录失败" ); } private static boolean login (Map<String, String> ui) { Connection conn = null ; PreparedStatement ps = null ; ResultSet re = null ; boolean flag = false ; try { Class.forName("com.mysql.cj.jdbc.Driver" ); conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test" ,"root" ,"xcfx" ); String sql = "select * from t_user where user = ? and pwd = ?" ; ps = conn.prepareStatement(sql); ps.setString(1 , ui.get("userName" )); ps.setString(2 , ui.get("pwd" )); re = ps.executeQuery(); if (re.next()) { flag = true ; } } catch (Exception e) { e.printStackTrace(); } finally { 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; } private static Map<String, String> intoUI () { Scanner sc = new Scanner (System.in); System.out.print("用户名:" ); String userName = sc.next(); System.out.print("密码:" ); String pwd = sc.next(); Map<String,String> userlogin = new HashMap <String,String>(); userlogin.put("userName" ,userName); userlogin.put("pwd" ,pwd); return userlogin; } }
Statement和PreparedStatement对比 Statement存在SQL注入问题
Statement编译一次执行一次,PreparedStatement编译一次执行n次,效率略高
PreparedStatement会在编译阶段做类型安全检查
什么时候用Statement?
项目支持SQL注入或需要进行SQL语句拼接的情况下,必须使用Statement
Statement用法示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 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(); 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(); 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完成增删改 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 package day1;import java.sql.*;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" ); 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中的事务是自动提交的,什么是自动提交?
只要执行任意一条SQL语句,则自动提交一次。这是JDBC默认的事务行为
但是在实际的业务中,通常都是n条DML语句共同联合才能完成的,
必须保证这些DML语句在同一个事务中同时成功或同时失败
2,以下程序先验证JDBC事务是否是自动提交机制
结论,Jdbc中只要执行任意一条DML语句,就提交一次
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 /-----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);
模拟银行账户转账
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 package day1;import java.sql.*;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(); ps.setDouble(1 ,10000 ); ps.setDouble(2 ,222 ); count += ps.executeUpdate(); 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
1 2 3 4 5 6 7 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);
实现模糊查询 工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 package util;import java.sql.*;public class JDBCutil { private JDBCutil () {} static { try { Class.forName("com.mysql.cj.jdbc.Driver" ); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection () throws SQLException { return DriverManager.getConnection("jdbc:mysql://localhost:3306/test" ,"root" ,"xcfx" ); } 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(); } } } }
测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package day1;import util.JDBCutil;import java.sql.*;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); ps.setString(1 ,"%x%" ); rs = ps.executeQuery(); 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,此数据就会锁住,其他事物不可修改