MyBatis核心配置文件详解多环境!--一个环境对应一个数据库开发环境和生产环境可以对应不同的环境 一般一个数据库对应一个sqlSessionFactory对象一个sqlSessionFactory对象对应一个环境 default表示默认环境-- environments defaultdevelopment environment iddevelopment transactionManager typeJDBC/ dataSource typePOOLED property namedriver valuecom.mysql.cj.jdbc.Driver/ property nameurl valuejdbc:mysql://localhost:3306/spring6/ property nameusername valueroot/ property namepassword valueroot/ /dataSource /environment environment idmybatisDB transactionManager typeJDBC/ dataSource typePOOLED property namedriver valuecom.mysql.cj.jdbc.Driver/ property nameurl valuejdbc:mysql://localhost:3306/spring1/ property nameusername valueroot/ property namepassword valueroot/ /dataSource /environment /environments那么java程序如何使用指定的环境呢public void testEnvironment() throws IOException { SqlSessionFactoryBuilder builder new SqlSessionFactoryBuilder(); // 没指定环境默认使用mybatis-config.xml中default指定的环境 SqlSessionFactory sqlSessionFactory builder.build(Resources.getResourceAsStream(mybatis-config.xml)); // 指定环境为development使用mybatis-config.xml中id为development的环境配置 SqlSessionFactory sqlSessionFactory2 builder.build(Resources.getResourceAsStream(mybatis-config.xml), development); }dataSource数据源dataSource的作用为程序提供connection对象凡是给程序提供connection对象的都叫做数据源。数据源是一套规范有JDK规定。dataSource是一个接口。数据库连接池就是一个数据源。type属性指定数据源类型。!-- type有三个值可选POOLED、UNPOOLED和JNDI UNPOOLED表示不使用连接池每次获取连接都会创建一个新的连接使用完后需要手动关闭连接否则会导致资源泄漏 适合于小型应用或者测试环境不适合于生产环境因为频繁创建和关闭连接会带来性能问题。 POOLED使用mybatis自带的连接池当有请求获取连接时会从连接池中获取一个可用的连接如果没有可用的连接且连接池 没有达到最大连接数限制则会创建一个新的连接并加入连接池当有请求释放连接时连接会被返回到连接池中而不是被关闭。 JNDI集成其他第三方的数据库连接池。 JNDI是一套规范大部分的web容器都实现了这套规范比如tomcat、jetty等都实现了JNDI规范提供了对数据库连接池的支持。 JNDI是Java命名目录接口。 type的值不同下面属性的name可选值也不同具体可查阅官方文档。 -- dataSource typePOOLED property namedriver valuecom.mysql.cj.jdbc.Driver/ property nameurl valuejdbc:mysql://localhost:3306/spring6/ property nameusername valueroot/ property namepassword valueroot/ /dataSource数据库连接池参数dataSource typePOOLED property namedriver valuecom.mysql.cj.jdbc.Driver/ property nameurl valuejdbc:mysql://localhost:3306/spring6/ property nameusername valueroot/ property namepassword valueroot/ !--连接池中允许的最大空闲连接数默认值为5。当连接池中的空闲连接数超过这个值时连接池会关闭多余的空闲连接以节省资源。-- property namepoolMaximumActiveConnections value8/ !--连接池中连接被占用的最长时间默认值为20000毫秒。当连接被占用的时间超过这个值时连接池会认为这个连接可能已经失效并将其关闭。 这个属性可以帮助连接池及时清理失效的连接避免资源泄漏和性能问题。 需要注意的是如果应用程序经常出现连接被占用时间过长的情况可能是因为数据库操作过于耗时或者连接池的配置不合理需要进行优化。 -- property namepoolMaximumCheckoutTime value10000/ !-- 每隔2秒打印日志并且获取连接对象-- property namepoolTimeToWait value2000/ !--最多空闲连接数-- property namepoolMaximumIdleConnections value5/ /dataSourceproperties标签!--properties是java.util.Properties类是一个map集合,key和value都是字符串类型 可以在mybatis-config.xml中定义一些全局的属性这些属性可以在mybatis-config.xml中的其他地方使用 也可以在xxxMapper.xml文件中使用。-- properties property namekey valuevalue/ property namejdbc.driver valuecom.mysql.cj.jdbc.Driver/ property namejdbc.url valuejdbc:mysql://localhost:3306/spring1/ property namejdbc.username valueroot/ property namejdbc.password valueroot/ /properties environments defaultdevelopment environment idmybatisDB transactionManager typeJDBC/ dataSource typePOOLED !--使用${}来取值-- property namedriver value${jdbc.driver}/ property nameurl value${jdbc.url}/ property nameusername value${jdbc.username}/ property namepassword value${jdbc.password}/ /dataSource /environment /environmentsproperties还有另外一种方式使用resource属性推荐!-- resource表示从类的根路径下查找资源-- properties resourcejdbc.properties /引入jdbc.properties配置文件其内容如下jdbc.dirvercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/mybatis?useSSLfalseserverTimezoneUTC jdbc.usernameroot jdbc.password123456mybatis事务控制一个SqlSession对象控制一个事务。保证一个线程对应一个SqlSession对象。所以要把SqlSession对象放在ThreadLocal里面。mybatis三大对象作用域SqlSessionFactoryBuilder这个类用来创建SqlSessionFactory对象它的作用域是方法作用域。只使用一次。SqlSessionFactorySqlSessionFactory一旦被创建就在应用的运行期间一直存在在应用运行期间不要重复创建多次。它的作用域是应用作用域。可以使用单例模式实现。SqlSession一个线程对应一个SqlSession实例。SqlSession的实例不是线程安全的因此不能被共享。它的作用域是请求或方法作用域。绝对不能将SqlSession实例放在一个类的静态域甚至一个类的实例变量也不行。免写Mapper接口的实现类使用javassist生成类javassist的效率高于cglibjavassist用于在内存中自动生成dao层的类。先引入依赖dependency groupIdorg.javassist/groupId artifactIdjavassist/artifactId version3.29.1-GA/version /dependency编写生成代码public void javavassistTest() throws Exception { // 1. 获取类池类池用来生成class ClassPool pool ClassPool.getDefault(); // 2.制造类 CtClass ctClass pool.makeClass(com.ali.dao.CarDao); // 3.制造方法 String methodStr public void save() { System.out.println(\保存车辆\); }; CtMethod ctMethod CtNewMethod.make(methodStr, ctClass); // 4.将方法添加到类中 ctClass.addMethod(ctMethod); // 5.将类写入内存 ctClass.toClass(); // 6.类加载 Class? aClass Class.forName(com.ali.dao.CarDao); // 7.创建对象 Object o aClass.newInstance(); // 8.获取方法 Method save aClass.getDeclaredMethod(save); // 9.执行方法 save.invoke(o); }注意高版本的jdkjdk8以上启动的时候会报错可以在启动时配置以下参数解决--add-opens java.base/java.langALL-UNNAMED--add-opens java.base/sun.net.utilALL-UNNAMED使用javassist动态生成类并实现接口public void testGenerateClass() throws Exception { // 1. 获取类池类池用来生成class ClassPool pool ClassPool.getDefault(); // 2.制造类 CtClass ctClass pool.makeClass(com.ali.dao.CarDaoImpl); // 3.制造接口 CtClass ctInterface pool.makeInterface(com.ali.dao.CarDao); // 4.将接口添加到类中,实现接口 ctClass.addInterface(ctInterface); // 5.实现接口中的所有方法 // 5.1 获取接口所有方法 CtMethod[] methods ctInterface.getDeclaredMethods(); // 5.2 遍历方法获取方法的签名并实现方法 for (CtMethod method : methods) { StringBuilder methodStr new StringBuilder(); methodStr.append(public ); methodStr.append(method.getReturnType().getName()); methodStr.append( ); methodStr.append(method.getName()); methodStr.append((); // 获取方法参数列表 CtClass[] parameterTypes method.getParameterTypes(); for (int i 0; i parameterTypes.length; i) { methodStr.append(parameterTypes[i].getName()).append( arg).append(i); if (i parameterTypes.length - 1) { methodStr.append(, ); } } methodStr.append() { System.out.println(\11111\)); // 添加return语句 if (!method.getReturnType().getName().equals(void)) { String simpleName method.getReturnType().getSimpleName(); if (void.equals(simpleName)) { }else if (int.equals(simpleName)) { methodStr.append(return 0); } else if (String.equals(simpleName)) { methodStr.append(return \你好\); } } methodStr.append( }); CtMethod ctMethod CtNewMethod.make(methodStr.toString(), ctClass); // 6.将方法添加到类中 ctClass.addMethod(ctMethod); } // 7.在内存中生成类同时将类加载到jvm中 Class? aClass ctClass.toClass(); // 8.创建对象,并将对象转换为接口类型 CarDao carDao (CarDao)aClass.newInstance(); carDao.delete(); }工具类GenerateDaoProxymybatis中不用写实现类其原理就是利用类似以下的工具类通过反射机制在内存中自动实现了接口的实现类。注意XxxxMapper.xml文件中的namespace必须是dao接口的全限定名称sql语句的id必须是dao接口的方法名。否则动态生成的类会报错// 这个类的作用是生成 DAO 接口的实现类使用 Javassist 来动态创建代理类 public class GenerateDaoProxy { // 生成dao接口的实现类额返回一个实现了 daoInterface 接口的类的实例 public static Object generateProxy(SqlSession sqlSession,Class daoInterface) { // 创建一个接口的实现类命名为 daoInterface 的名字加上 Proxy String proxyClassName daoInterface.getName() Proxy; try { ClassPool pool ClassPool.getDefault(); CtClass ctClass pool.makeClass(proxyClassName); // 让这个新类实现 daoInterface ctClass.addInterface(pool.makeInterface(daoInterface.getName())); // 为每个方法添加一个简单的实现 for (CtMethod method : ctClass.getDeclaredMethods()) { StringBuilder methodStr new StringBuilder(); methodStr.append(public ); methodStr.append(method.getReturnType().getName()); methodStr.append( ); methodStr.append(method.getName()); methodStr.append((); // 获取方法参数列表 CtClass[] parameterTypes method.getParameterTypes(); for (int i 0; i parameterTypes.length; i) { methodStr.append(parameterTypes[i].getName()).append( arg).append(i); if (i parameterTypes.length - 1) { methodStr.append(, ); } } methodStr.append() { ); methodStr.append(org.apache.ibatis.session.SqlSession sqlSession com.ali.utils.SqlSessionUtil.openSqlSession();); // 需要知道是什么类型的sql语句 // mybatis框架规定sql语句的id不能随便写namespace必须是接口的全限定名id必须是接口的方法名 // 所以可以通过反射获取方法的全限定名和方法名来获取sql语句的id String sqlId daoInterface.getName() . method.getName(); SqlCommandType sqlCommandType sqlSession.getConfiguration().getMappedStatement(sqlId).getSqlCommandType(); if (sqlCommandType SqlCommandType.INSERT) { } else if (sqlCommandType SqlCommandType.UPDATE) { // 参数名必须是 arg0因为在上面定义方法的时候参数名是 arg0如果参数名不一致就会报错找不到参数 methodStr.append(return sqlSession.update(\).append(sqlId).append(\, arg0);); } else if (sqlCommandType SqlCommandType.DELETE) { }else if (sqlCommandType SqlCommandType.SELECT) { String returnName method.getReturnType().getName(); methodStr.append(return (returnName)sqlSession.selectOne(\).append(sqlId).append(\, arg0);); } methodStr.append(}); CtMethod ctMethod CtMethod.make(methodStr.toString(), ctClass); ctClass.addMethod(ctMethod); } // 将生成的类加载到 JVM 中并返回一个实例 Class proxyClass ctClass.toClass(); return proxyClass.newInstance(); } catch (Exception e) { e.printStackTrace(); return null; } }实际开发中在mybatis框架中可以使用SqlSession对象的getMapper方法获取mybatis框架为我们生成的代理类实例// 通过getMapper获取 carDao 对象 private CarDao carDao SqlSessionUtil.openSqlSession().getMapper(CarDao.class);