http://mybatis.org/spring/zh/getting-started.html https://mybatis.net.cn/getting-started.html

一、回顾 jdbc

获取链接—》预编译sql—》设置参数—》执行sql

  1. public class JdbcReview {
  2. public static void main(String[] args) {
  3. try {
  4. Class.forName("com.mysql.cj.jdbc.Driver'");
  5. } catch (ClassNotFoundException e) {
  6. e.printStackTrace();
  7. }
  8. Connection connection = null;
  9. Statement statement = null;
  10. ResultSet resultSet = null;
  11. try {
  12. connection = DriverManager.getConnection("");
  13. statement = connection.createStatement();
  14. resultSet = statement.executeQuery("select * from user");
  15. List<User> users = new ArrayList<>();
  16. while (resultSet.next()) {
  17. User user = new User();
  18. user.setId(resultSet.getInt(1));
  19. user.setAge(resultSet.getInt(2));
  20. user.setName(resultSet.getString(3));
  21. users.add(user);
  22. }
  23. } catch (Exception e) {
  24. e.printStackTrace();
  25. } finally {
  26. if (resultSet != null) {
  27. try {
  28. resultSet.close();
  29. } catch (SQLException throwables) {
  30. throwables.printStackTrace();
  31. }
  32. }
  33. if (statement != null) {
  34. try {
  35. statement.close();
  36. } catch (SQLException throwables) {
  37. throwables.printStackTrace();
  38. }
  39. }
  40. if (connection != null) {
  41. try {
  42. connection.close();
  43. } catch (SQLException throwables) {
  44. throwables.printStackTrace();
  45. }
  46. }
  47. }
  48. }
  49. }
  • 1、statement中的execute方法
    • boolean execute(String sql) throws SQLException;
      • true:第一个结果是一个结果集
      • false:更新操作或者无结果集
  • 2、executeUpdate
    • int executeUpdate(String sql) throws SQLException;
      • (1) DML语言的操作行数
  • 3、executeQuery
    • ResultSet executeQuery(String sql) throws SQLException;
      • 查询返回结果集

二、整体架构设计

image.png

三、sql解析过程

  1. interface UserMapper {
  2. @Select("SELECT * FROM user WHERE age = #{age} and name = #{name}")
  3. List<User> selectUserList(int age, String name);
  4. }
  5. public class MyBatisMapperProxy {
  6. public static void main(String[] args) {
  7. UserMapper userMapper = (UserMapper) Proxy.newProxyInstance(MyBatisMapperProxy.class.getClassLoader(), new Class<?>[]{UserMapper.class}, new InvocationHandler() {
  8. @Override
  9. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  10. Select annotation = method.getAnnotation(Select.class);
  11. Map<String, Object> nameArgMap = buildMethodArgNameMap(method, args);
  12. if (annotation != null) {
  13. String[] value = annotation.value();
  14. String sql = value[0];
  15. // 解析sql,用参数替换 #{}
  16. sql = parseSql(sql, nameArgMap);
  17. // 这就拿到组装好的sql了
  18. System.out.println(sql);
  19. System.out.println(method.getReturnType());
  20. System.out.println(method.getGenericReturnType());
  21. System.out.println(method.getGenericReturnType().getClass());
  22. }
  23. return null;
  24. }
  25. });
  26. userMapper.selectUserList(1, "king");
  27. }
  28. public static String parseSql(String sql, Map<String, Object> nameArgMap) {
  29. StringBuilder stringBuilder = new StringBuilder();
  30. int length = sql.length();
  31. for (int i = 0; i < length; i++) {
  32. char c = sql.charAt(i);
  33. if (c == '#') {
  34. int nextIndex = i + 1;
  35. char nextChar = sql.charAt(nextIndex);
  36. if (nextChar != '{') {
  37. throw new RuntimeException(String.format("这里应该为#{\nsql:%s\nindex:%d", stringBuilder.toString(), nextIndex));
  38. }
  39. StringBuilder argSB = new StringBuilder();
  40. i = parseSQLArg(argSB, sql, nextIndex + 1);
  41. String argName = argSB.toString();
  42. Object argValue = nameArgMap.get(argName);
  43. stringBuilder.append(argValue.toString());
  44. continue;
  45. }
  46. stringBuilder.append(c);
  47. }
  48. return stringBuilder.toString();
  49. }
  50. private static int parseSQLArg(StringBuilder argSB, String sql, int nextIndex) {
  51. for (; nextIndex < sql.length(); nextIndex++) {
  52. char c = sql.charAt(nextIndex);
  53. if (c != '}') {
  54. argSB.append(c);
  55. continue;
  56. }
  57. // 找到右括号就返回
  58. if (c == '}') {
  59. return nextIndex;
  60. }
  61. }
  62. throw new RuntimeException(String.format("缺少右括号#{\nsql:%s\nindex:%d", sql, nextIndex));
  63. }
  64. public static Map<String, Object> buildMethodArgNameMap(Method method, Object[] args) {
  65. HashMap<String, Object> map = new HashMap<>();
  66. Parameter[] parameters = method.getParameters();
  67. if (parameters.length != args.length) {
  68. System.out.println("s错误。。。");
  69. throw new RuntimeException("error,,.....");
  70. }
  71. int index[] = {0};
  72. Arrays.stream(parameters).forEach(parameter -> {
  73. // 注意:使用此方法需要开启IDEA支持带参数名编译,否则会出现 arg0,arg1
  74. // https://blog.csdn.net/lcgoing/article/details/88537836
  75. // Preferences -> "Build, Execution, Deployment" -> Compiler -> "Java Compiler"
  76. // "Project bytecode version"设置为1.8
  77. // "Additional command line parameters"添加"-parameters"
  78. String name = parameter.getName();
  79. System.out.println(name);
  80. map.put(name, args[index[0]]);
  81. index[0]++;
  82. });
  83. return map;
  84. }
  85. }

这里拿到了解析完的sql,然后将这个sql放到 第一节 里执行即可。
这就是一个简化简化的mybatis。。。。