• [技术干货] Spring整合Mybatis方式二 - SqlSessionTemplate【转】
    前置工作导包:mybatis-spring、mysql-connector-java、mybatis、spring-webmvc、spring-jdbc实体类DAO层两个文件(接口、xml文件);Service层的接口spring-dao.xml核心:sqlSessionTemplate配置<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg index="0" ref="sqlSessionFactory"/></bean>完整代码:<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config/> <!-- 1.使用Spring配置dataSource,相当于myBatis配置文件的<environments>。需要spring-jdbc包--> <context:property-placeholder location="classpath:db.properties"/> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <!-- 2.配置SqlSessionFactoryBean 等同于SqlSessionFactory 做读取数据源以及注册mapper.xml的工作--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="mapperLocations" value="classpath:com/ylzl/mapper/*.xml"/> <!-- 配置MyBatis的全局配置文件:mybatis-config.xml --> <property name="configLocation" value="classpath:mybatis-config.xml"/> </bean> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg index="0" ref="sqlSessionFactory"/> </bean> <bean id="bookMapper" class="com.ylzl.mapper.BookMapperImpl"> <property name="sqlSession" ref="sqlSession"/> </bean> <bean id="bookServiceImpl" class="com.ylzl.service.BookServiceImpl"/></beans>DAO层新加Dao接口的实现类:私有化sqlSessionTemplatepublic class BookMapperImpl implements BookMapper { //sqlSession不用我们自己创建了,Spring来管理 private SqlSessionTemplate sqlSession; public void setSqlSession(SqlSessionTemplate sqlSession) { this.sqlSession = sqlSession; } @Override public Book getBookById(Integer bookID) { BookMapper mapper = sqlSession.getMapper(BookMapper.class); return mapper.getBookById(bookID); }}注:注册bean实现(dao接口实现类的)Service层-实现类public class BookServiceImpl implements BookService{ @Autowired private BookMapperImpl bookMapperImpl; @Override public Book getBookById(Integer bookID) { return bookMapperImpl.getBookById(bookID); }}测试ApplicationContext context=new ClassPathXmlApplicationContext("spring-dao.xml"); BookService bookServiceImpl = context.getBean("bookServiceImpl", BookService.class); Book book = bookServiceImpl.getBookById(2); System.out.println(book);优化:SqlSessionDaoSupportmybatis-spring1.2.3版以上的才有这个1.修改dao层实现类public class BookMapperImpl extends SqlSessionDaoSupport implements BookMapper { @Override public Book getBookById(Integer bookID) { SqlSession sqlSession = getSqlSession(); BookMapper mapper = sqlSession.getMapper(BookMapper.class); return mapper.getBookById(bookID); }}2.注册bean实现(dao接口实现类:BookMapperImpl)<bean id="bookMapper" class="com.ylzl.mapper.BookMapperImpl"> <!-- 注意这行代码 --> <property name="sqlSessionFactory" ref="sqlSessionFactory"/></bean>3.删除<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg index="0" ref="sqlSessionFactory"/></bean>转载自https://www.cnblogs.com/yulingzhiling/p/18100409
  • [技术干货] Spring整合Mybatis方式一 - 常规整合 - 注册映射器【转】
    前置工作导包(mybatis-spring、mysql-connector-java、mybatis、spring-webmvc等)实体类DAO层两个文件(接口、xml文件);Service层的接口编写Spring管理mybatis的xml-spring-dao.xml核心代码(两种方式实现)第一种:xml<!-- 将会话工厂对象托管给spring --><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <!-- 配置MyBatis的全局配置文件:mybatis-config.xml --> <property name="configLocation" value="classpath:mybatis-config.xml"/> <property name="mapperLocations" value="classpath:com/ylzl/mapper/*.xml"/></bean> <!-- 注册映射器:将映射器接口托管到Spring中 --><bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> <property name="mapperInterface" value="com.ylzl.mapper.UserMapper" /></bean><!-- MapperFactoryBean对象 负责 SqlSession 的创建和关闭,如果使用了 Spring 事务,当事务完成时,session 将会被提交或回滚。最终任何异常都会被转换成 Spring 的 DataAccessException 异常--><!-- mybatis映射器接口(如:interface UserMapper):sql部分可以使用mybatis的xml配置,与接口在同一路径下,会被 MapperFactoryBean自动解析-->第二种:annotation方式@Beanpublic SqlSessionFactory sqlSessionFactory() throws Exception { SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(dataSource()); return factoryBean.getObject();} @Beanpublic MapperFactoryBean<UserMapper> userMapper() throws Exception { MapperFactoryBean<UserMapper> factoryBean = new MapperFactoryBean<>(UserMapper.class); factoryBean.setSqlSessionFactory(sqlSessionFactory()); return factoryBean;}完整xml文件<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config/> <!-- 使用Spring配置dataSource 相当于MyBatis配置文件的<environments>--><!-- 需要spring-jdbc包--> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/ssmbuild"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean> <!-- 配置SqlSessionFactoryBean 等同于SqlSessionFactory 做读取数据源以及注册mapper.xml的工作--><!-- SqlSessionFactoryBean会调用类中的getObject()方法,返回SqlSessionFactory--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="mapperLocations" value="classpath:com/ylzl/mapper/BookMapper.xml"/> </bean><!-- 获得Mapper代理对象 等同于getMapper()--> <bean id="BookMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> <property name="mapperInterface" value="com.ylzl.mapper.BookMapper" /> </bean> <!-- 注册employeeServiceImpl--> <bean id="bookServiceImpl" class="com.ylzl.service.impl.BookServiceImpl"/></beans>重新编写Service实现类public class BookServiceImpl implements BookService{ private BookMapper bookMapper; @Autowired //需要spring-aop包 public BookServiceImpl(BookMapper bookMapper) { this.bookMapper = bookMapper; } @Override public Book getBookById(Integer bookID) { return bookMapper.getBookById(bookID); }}测试ApplicationContext context=new ClassPathXmlApplicationContext("spring-dao.xml");BookService bookServiceImpl = context.getBean("bookServiceImpl", BookService.class);Book book = bookServiceImpl.getBookById(2);System.out.println(book);改进注册映射器方式:使用发现映射器方式MapperFactoryBean注册映射器的最大问题,就是需要一个个注册所有的映射器,而实际上mybatis-spring提供了扫描包下所有映射器接口的方法。注意:以下两种配置方法,均可替换上述MapperFactoryBean配置,而其余代码与配置不变方式一: 配置扫描器标签1.与上面配置MapperFactoryBean不同,该配置无需注入SqlSessionFactory,它会自动匹配已有的会话工厂bean2.如果配置了多个DataSource,也就是多个sqlSessionFactory时,可以使用factory-ref参数指定需要的会话工厂<mybatis:scan base-package="com.ylzl.dao" factory-ref="sqlSessionFactory" /> <!-- annotation方式-注解配置类:@MapperScan(basePackages = "com.ylzl.dao", sqlSessionFactoryRef = "sqlSessionFactory") --> <!-- 省略其他... -->方式二: MapperScannerConfigurer类1.与上面标签的功能差不多,同样是扫描基准包,自动注入会话工厂2.如果要更换注入的会话工厂,不同于常用的ref引入bean,而是使用value指定bean名,且属性是sqlSessionFactoryBeanName<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.ylyl.mapper" /> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /></bean>annotation方式@Beanpublic MapperScannerConfigurer mapperScannerConfigurer() { MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer(); mapperScannerConfigurer.setBasePackage("com.ylzl.dao"); mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory"); return mapperScannerConfigurer;}转载自https://www.cnblogs.com/yulingzhiling/p/18099455
  • [技术干货] Mybatis中处理特殊SQL处理逻辑解析【转】
    0、前言在MyBatis中可能会有一些特殊的SQL需要去执行,一般就是模糊查询、批量删除、动态设置表名、添加功能获取自增的主键这几种,现在分别来进行说明。为了方便演示 ,定义了访问的接口public interface SQLMapper {     /**      * 根据用户名模糊查询用户信息      */     List<User> getUserByLike(@Param("username") String username);     /**      * 批量删除      */     int deleteMore(String ids);     /**      * 查询指定表中的数据      */     List<User> getUserByTableName(String tableName);     /**      * 添加用户      */     void insetUser(User user); }1、模糊查询模糊查询非常的有用,对于一些访问量不是很大的搜索都是直接使用模糊查询的方式来做的。SQLMapper类:public interface SQLMapper {     /**      * 根据用户名模糊查询用户信息      */     List<User> getUserByLike(@Param("username") String username); }对于SQLXml的编写;<!--    List<User> getUserByLike(@Param("username") String username);--> <!--    使用#{},因为包括在单引号里,会被认为是字符串的一部分:select * from t_user where username like '%#{username}%'--> <!--    三种方式-->     <select id="getUserByLike" resultType="User">      <!--  第一种 select * from t_user where username like '%${username}%'        第二种 select * from t_user where username like concat('%', #{username}, '%')-->        <!--第三种 推荐使用-->         select * from t_user where username like "%"#{username}"%"     </select>需要注意的是Mybatis对JDBC进行了进一步封装,使得我们可以更加便捷的使用Java操作数据库。Mybatis获取参数值有两种方式:#{}和${}在大部分情况下,#{}和${}都能相互替代,使用两者之一即可,更加推荐使用#{},因为可以防止SQL注入问题,但是由于#{}和${}本质上的不同,部分SQL语句使用#{}和${}需要格外注意#{}和${}本质区别#{}本质上是占位符赋值,为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号${}本质上是字符串拼接,为字符串类型或日期类型的字段进行赋值时,需要手动加单引号这个场景下,使用#{}和${}都能达到目的,但是用法稍有不同如果是直接使用<select id="selectLike" resultType="pojo.User">     select * from user where user_name like '%#{username}%' </select>将#{}换成${}<select id="selectLike" resultType="pojo.User">     select * from user where user_name like '%${username}%' </select>成功执行如果非要使用#{},也不是没有解决办法使用""拼接<select id="selectLike" resultType="pojo.User">     select * from user where user_name like "%"#{username}"%" </select>或者是使用concat()函数来拼接<select id="selectLike" resultType="pojo.User">     select * from user where user_name like concat('%',#{likeString},'%') </select>2、动态表名在某些场景下,我们需要来回操作各种表,但SQL语句功能一致,这时我们可以使用动态表名,即传参为表名类型,这时就要从#{}和${}中进行选择了Mapper接口List<User> selectAllFromTable(@Param("tableName") String tableName);如果是直接使用#{}的方式<select id="selectAllFromTable" resultType="pojo.User">     select * from #{tableName} </select>结果报错,原因在于#{}为占位符赋值,传参为String的话就会自动补上单引号'',而表名不允许添加单引号,所以导致出错。直接使用${}的方式<select id="selectAllFromTable" resultType="pojo.User">     select * from ${tableName} </select>结果成功了,所以在动态表名的情况下,我们只能使用${}3、获取自增的组件需要在xml中配置 useGeneratedKeys , keyProperty 两个属性的值.<!--    void insetUser(User user);--> <!--    方法的返回值是固定的         useGeneratedKeys    设置当前标签中的sql使用了自增的主键 (id)         keyProperty         将自增的主键的值 赋值给 传输到映射文件中的参数的某个属性(user.id) -->     <insert id="insetUser" useGeneratedKeys="true" keyProperty="id">         insert into t_user values(null, #{username}, #{password},#{age},#{gender},#{email})     </insert>4、批量删除有些场景,需要我们根据id数组批量删除记录,这个时候也有一些坑由于id数组的长度是不确定的,所以我们不能确定参数的个数,但是我们可以使用in关键字,这个时候我们将id数组转为字符串进行传参就好了。[1,2,3] => 1,2,3Mapper接口Integer deleteByIds(String Ids);使用#{}<delete id="deleteByIds">     delete from user where id in (#{ids}) </delete>结果报错,原因在于in后面的小括号里面的'1,2,3'为字符串类型且为一个整体,与整数类型不符,因此不能使用#{}使用${}<delete id="deleteByIds">     delete from user where id in (${ids}) </delete>结果成功了,看来有些场景不得不使用${}
  • [技术干货] 为什么很多大厂不用Mybatis
    最近接手一个使用 mybatis plus开发的项目, 大概看下来, mybatis plus真的不适合企业级开发。如果是个人的小项目,快速上线的demo原型,使用mybatis plus固然是比较快的。但是作为一个企业级大项目, 特别是 对于表、字段、索引、查询 都要慎之又慎的项目,使用mybatis plus很不明智。虽然MyBatis有很多优点,但是一些大厂不使用MyBatis的原因可能有以下几点:技术栈限制:一些大厂可能已经有了自己的技术栈和框架,比如使用了Hibernate、Spring Data JPA等,这些框架已经提供了相应的持久层解决方案,无需使用MyBatis。此外,一些大厂可能更倾向于使用与自己已有技术栈更为匹配的框架。性能要求:虽然MyBatis在许多场景下表现出色,但在一些高并发、大数据处理的场景下,MyBatis可能无法满足性能要求。而一些大厂需要处理海量数据和高并发请求,因此需要使用更为高性能的解决方案,如使用原生SQL语句或存储过程等。团队技能:一些大厂可能更倾向于使用Java语言和相关技术栈进行开发,而MyBatis是基于Java语言的持久层框架。如果团队成员对其他语言或技术栈更为熟悉,可能会选择其他持久层解决方案。维护成本:虽然MyBatis相对简单易用,但与一些自动化程度更高的框架相比,MyBatis可能需要更多的维护成本。例如,MyBatis需要手动编写SQL语句和映射配置,而在一些其他框架中,这些工作可以自动完成。对于底层的SQL的掌控明显变弱。Mybatis有着自己固有的格式,但当面对一些复杂SQL的时候,还是只能人工手动进行编写SQL和java代码的柔和,在多人协作的情况下,缺陷被放大。在优化或者重构的时候,非常麻烦。容易写出来暴力代码,如果数据量大,调优处理不是很方便。不易形成文档等可落地的资料。 代码和sql柔和在一起, 规模太大了之后,整理资料都很困难。不如直接在mapper里 好 管理。总之,虽然MyBatis有很多优点,但一些大厂不使用MyBatis的原因可能是由于技术栈限制、性能要求、团队技能和维护成本等因素的考虑。在选择持久层解决方案时,需要根据实际需求和场景进行综合考虑。
  • [技术干货] Java 操作Mybatis
    什么是MyBatisMyBatis本是Apache的一个开源项目iBatis,2010年这个项目由Apache Software Foundation迁移到了Google Code,并且改名为MyBatis。2013年11月迁移到Github。MyBatis是一个基于Java的持久层框架,提供的持久层框架包括SQL Maps和Data Access Objects(DAO),它消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs(Plain Old Java Objects,普通的Java对象)映射为数据库中的记录。Java操作Mybatis在Java中操作Redis,我们通常需要使用一个库,例如Jedis或Lettuce。以下是使用Jedis库进行基本操作的示例。首先,你需要在你的项目中添加Jedis的依赖。如果你使用Maven,你可以在你的pom.xml文件中添加以下依赖:<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>3.7.0</version> <!-- 版本可能会有所变化,取决于你查看此答案时的最新版本 --> </dependency>然后你可以使用以下Java代码进行基本的Redis操作:import redis.clients.jedis.Jedis; public class Main { public static void main(String[] args) { // 创建连接对象 Jedis jedis = new Jedis("localhost"); System.out.println("Connection to server successfully"); // 设置数据 jedis.set("foo", "bar"); System.out.println("Data set in Redis: " + jedis.get("foo")); // 获取存储的数据并输出 System.out.println("Stored data in Redis: " + jedis.get("foo")); } }这是一个非常基础的例子,它连接到了在本地运行的Redis服务器(这是默认设置),然后设置了一个键值对("foo", "bar"),并从Redis获取这个值然后打印出来。在实际应用中,你可能需要处理更复杂的情况,例如使用密码保护你的连接、从远程服务器获取数据、处理并发问题等。在这些情况下,你可能需要使用更高级的库,例如Redisson,它提供了更多的功能和更好的抽象。
  • [技术干货] MyBatis源码解析【转】
    Xml解析的常见方式:DOM SAX Xpath ,Mybatis使用的时Xpath,因其足够简单。流程图:源码分析流程图Mybatis核心对象mybatis核心对象分为两类:存储类对象和 操作类对象 SqlSesson封装了JDBC(Statement,Prepared Statement ,Callable Statement ,ResultSet),还包含了SqlSessionFactory,mybatis-config,.xml,Mapper.xml的信息Mybatis的核心对象及其作用mybatis核心对象存储类对象概念:在java中(jvm)对Mybatis相关的配置信息进行封装MappedStatement 小结:使用建造者模式构建内部有configuration便于操作和使用含有xml某个节点中的完整信息操作类对象Executor:Mybatis的执行器主要功能:增删改 update查 query事务 提交 回滚缓存Executo功能Executo的实现类SimpleExecutor 常用Excutor ReuseExecutor 复用Excutor 条件和参数都不改变的情况下可以使用 BatchExecutor JDBC中批处理 批处理;一个连接上进行多个sqlExecutor小结 :调用StatementHandler来进行数据库相关的改、查操作维护缓存StatementHandler是Mybatis真正封装JDBC Statement 的部分 , 是Mybatis访问数据库的核心。实现了Excutor中增删改查的功能ParameterHandler解决sql中的参数类型和占位符(?,?)ResultSetHandler对JDBC中 查询结果集ResultSet封装TypeHandler类型转化 例如:将java类型转化为数据库类型(String varchar)缓存一级缓存在BaseExecutor中实现 二级缓存使用装饰器模式在CachingExecutor中实现缓存逻辑图mybaits缓存逻辑图一级缓存命中场景(会话级别缓存)运行时参数相关:sql语句 和参数相同statement的id需要相同sqlsession也必须相同RowBounds返回行范围必须相同操作与配置相关:①②③ 都会调用clearLocalCache()来对缓存进行清空未手动清空 (提交 回滚)未调用flushCache == true 的查询未执行update操作 update操作会清空全部缓存缓存作用域 不是STATEMENTspring整合mybatis 以及缓存失效原因使用拦截器(动态代理)来控制方法的调用,最终达到实现事务的效果二级缓存作用范围是整个应用,而且可以跨线程调用使用流程:二级缓存执行流程使用场景运行时参数相关:会话提交之后sql语句 和参数相同statement的id需要相同RowBounds 返回行范围必须相同为何提交之后才能命中缓存会话1和会话2本来是不可见的,但是使用二级缓存后边的可见了。例如: 会话2进行了查询、修改操作,若此时将操作填充到二级缓存中,会话1此时进行查询,拿到了这条缓存数据。而后会话2 进行了回滚操作,会话1拿到的数据就是数据库中不存在的,导致了脏读。解决方案:二级缓存存储图为每个会话创建一个事务缓存管理器(transactionCaches),每次访问一个新的xxxMapper都会创建一个暂存区,对应着相应的缓存区Mybatis中使用的设计模式单例模式configuration 使用单例 保证整个程序运行期间都可使用,且不重复创建,放置浪费资源构造器模式在Mybatis的初始化的主要工作是加载并解析mybatis-config.xml的配置文件、映射配置文件以及相关的注解信息。因为使用了建造者模式,BashBuilder抽象类即为建造者接口的角色public abstract class BaseBuilder { //需要配置,类型别名注册,类型处理器注册3个东西 protected final Configuration configuration; protected final TypeAliasRegistry typeAliasRegistry; protected final TypeHandlerRegistry typeHandlerRegistry; public BaseBuilder(Configuration configuration) { this.configuration = configuration; this.typeAliasRegistry = this.configuration.getTypeAliasRegistry(); this.typeHandlerRegistry = this.configuration.getTypeHandlerRegistry(); } ……………… }适配器模式(Excutor 等核心对象,使用缺省适配器模式) 使用extends关键字来继承,只用实现想实现的功能interface Test{ void eat(); void drink(); void walk(); } abstract class abstractClass implements Test{ public void eat() { // TODO Auto-generated method stub } @Override public void drink() { } @Override public void walk() { } } class eatClass extends abstractClass{ @Override public void eat() { super.eat(); } } class drinkClass extends abstractClass{ @Override public void eat() { super.eat(); } }代理模式(动态代理)RoleMapper roleMapper=sqlSession.getMapper(RoleMapper.class); 实现类使用动态字节码技术来创建,在jvm中运行时创建 等价于 Proxy.newProxyInstance(Test.class.getClassLoader(),new Class[]{RoleMapper.class}, new MyMapperProxy(sqlSession,RoleMapper.class));工厂模式使用mapper工厂来创建mapperMapperProxyFactory 和 MapperProxy protected T newInstance(MapperProxy<T> mapperProxy) { //用JDK自带的动态代理生成映射器 return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); }门面模式sqlsession使用门面模式,只定义api 具体的使用让Executor来进行实现装饰器模式在不改变原有类结构和继承的情况下,通过包装原对象去扩展一个新功能Caching Executor 实现二级缓存,而其他的操作,如同获取连接等操作BaseExecutor已经做了,直接使用BaseExecutor。
  • [技术干货] mybatis和hibernate比较
    1.开发速度对比首先,hebirnate比mybatis掌握起来较难,mybatis相对简单但是也相对简陋。对于一些只使用简单的增删改查,而很少复杂查询的项目,使用hibernate开发比较快,因为其已经封装好了sql语句。但是对于复杂查询较多的项目,就需要使用mybatis来开发较为合适。2.开发工作量两者都有相应的代码生成器,可以生成简单的dao层代码。但是对于高级查询,mybatis需要手动编写sql语句,并且需要写resultMap,但是hibernate有完整的映射机制,开发人员不需要关心sql的生成和结果映射。3.sql优化方面hibernate会将表中所有字段查询出来,会损耗一定的性能。虽然hibernate也可以自己写sql语句,但是破坏了hibernate开发的简洁性。而mybatis手动编写sql,可以指定查找的字段。Hibernate HQL语句的调优需要将SQL打印出来,而Hibernate的SQL被很多人嫌弃因为太丑了。。MyBatis的SQL是自己手动写的所以调整方便。但Hibernate具有自己的日志统计。Mybatis本身不带日志统计,使用Log4j进行日志记录。4.数据库移植性hibernate通过它强大的映射结构和hql语言,降低了对象与数据库(Oracle、MySQL等)的耦合性,而mybatis由于需要手写sql,因此与数据库的耦合性直接取决于程序员写sql的方法,如果sql不具通用性而用了很多某数据库特性的sql语句的话,移植性也会随之降低很多,成本很高。5.缓存MyBatis的二级缓存配置都是在每个具体的表-对象映射中进行详细配置,这样针对不同的表可以自定义不同的缓存机制。并且Mybatis可以在命名空间里共享相同的缓存配置和实例,通过Cache-ref来实现。而Hibernate对查询对象有着良好的管理机制,用户无需关心SQL。所以在使用二级缓存时如果出现脏数据,系统会报出错误并提示。
  • [技术干货] mybaits-plus lambdaQuery() 和 lambdaUpdate() 比较常见的使用方法【转】
    简介 MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。 愿景 我们的愿景是成为 MyBatis 最好的搭档,就像 魂斗罗 中的 1P、2P,基友搭配,效率翻倍。  无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere ) 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库 内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作 前言 采用简明的拉姆达表达式查询数据 提示:以下是本篇文章正文内容,下面案例可供参考 学生类 @Data public class Student {      /*学号*/     private Integer sno;     /*名称*/     private String name;     /*年龄*/     private int age;     /*班级名称*/     private String className;     /*地址*/     private String address;  }  mybaits-plus 简单明了的,开发中比较常见的使用方式 根据id查询 Student byId = studentService.getById(1);带条件的查询 根据id查询对象 Student one = studentService.lambdaQuery().eq(Student::getSno, 1).one();查询学生集合 List<Student> list = studentService.list(); 带条件的集合查询 根据地址查询所在上海的学生 List<Student> studentList = studentService.lambdaQuery().eq(Student::getAddress, "上海").list(); 常见的分页查询        根据id删除 studentService.removeById(1); 带条件的删除 删除名称为张三 年龄等于15的学生 studentService.lambdaUpdate().eq(Student::getName,"张三").eq(Student::getAge,15).remove(); 修改 根据id修改        Student student = new Student();         student.setSno(1);         student.setAddress("上海");         student.setClassName("一年级一班");         studentService.updateById(student); 修改 将学号为1的学生的地址修改为湖南 studentService.lambdaUpdate().set(Student::getAddress,"湖南").eq(Student::getSno,1).update();  < <= > >= <> lt() le() gt() ge() ne()查询年龄小于20的学生集合 其他以此内推 List<Student> list1 = studentService.lambdaQuery().lt(Student::getAge, 20).list(); ———————————————— 版权声明:本文为CSDN博主「来自上海的这位朋友」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/Susan003/article/details/126732053 
  • [技术干货] MyBatis的xml传参方式
    Java的Mybatis中xml的传参方式1.@Param值传递//mapper int insertBlog(@Param("name") String name,@Param("age") int age); //xml <insert id="insertBlog"> insert into blog(name,age) values(#{name},#{age}); </insert>2.对象传值//mapper int insertBlog(Blog blog); //xml <insert id="insertBlog" parameterType="com.example.entity.Blog"> insert into blog(name,age) values(#{name},#{age}); </insert> //service Blog blog=new Blog(); blog.setAge(13); blog.setName("zzl3"); blogMapper.insertBlog(blog);3.map传值//mapper int insertBlog(Map<String,Object> map); //xml <insert id="insertBlog" parameterType="map"> insert into blog(name,age) values(#{name},#{age}); </insert> //service Map<String,Object> map = new HashMap<>(); map.put("name","zzl4"); map.put("age",14); blogMapper.insertBlog(map);
  • [其他] MyBatis-Plus分页——PageHelper和IPage介绍
    两个都用于分页,常用的应该是PageHelper了,理解了一下源码后发现IPage比PageHelper好用。 使用方法是 PageHelper.startPage()然后后边写sql就可以。 紧接着的一个sql起作用。 IPage则需要在dao层传入IPage的实现类Page对象,该对象实现了IPage。 区别: PageHelper内部原理是将传入的页码和条数赋值给了Page对象,保存到了一个本地线程ThreadLoacl中, 然后会进入Mybatis的拦截器中。然后再拦截器中获取本地线程中保存的分页的参数。最后再将这些分页 参数和原本的sql以及内部定义好的sql进行拼接完成sql的分页处理。中间会进行判断该sql 的类型是查询 还是修改操作。如果是查询才会进入分页的逻辑并判断封装好的Page对象是否是null null则不分页,否则分页。 IPage内部原理也是基于拦截器,但是这个拦截的是方法以及方法中的参数,这个也会判断是否是查询操作。 如果是查询操作,才会进入分页的处理逻辑。 进入分页逻辑处理后,拦截器会通过反射获取该方法的参数 进行判断是否存在IPage对象的实现类。如果不存在则不进行分页,存在则将该参数赋值给IPage对象。 然后进行拼接sql的处理完成分页操作。 但是使用IPage需要注入一个bean拦截器交给spring进行管理。如下。否则不会进行拦截。 @Bean public PaginationInterceptor paginationInterceptor() { return new PaginationInterceptor(); } pom: springboot使用的是2.1.0 <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>${mybatisplus.version}</version><!-- 3.2.0 --> <exclusions> <exclusion> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> </exclusion> </exclusions> </dependency> IPage的好处: 适用于多方言的数据库类型;例如 MySQL、Oracle、SqlServer等。 注意:如果两个一起用,内部会先执行IPage的拦截器并进行分页 然后会进入的PageHelper的分页处理。 优先使用的是IPage并且PageHelper会出现问题(不论谁前谁后)。返回Page是没问题的, 但是如果返回集合的结果集使用PageInfo进行分页就会出现问题。PageHelper只会有指定条数的数据。 所以只能使用一个,如果两个一起使用,则使用IPage返回Page接收。不可已使用PageInfo进行接收数据。 (当然这个的前提也是对同一个sql进行分页操作并返回的集合结果集)转自:https://blog.csdn.net/bingguang1993/article/details/119936178
  • [技术干货] UpdateWrapper 的一些主要特性和使用方法
    UpdateWrapper 是 MyBatis-Plus 框架中的一个更新条件构造器,用于构建 SQL 更新语句的更新条件。通过 UpdateWrapper,你可以使用链式编程风格来构建更新条件,并将其传递给 MyBatis-Plus 提供的 update 方法,以实现灵活的更新操作。以下是 UpdateWrapper 的一些主要特性和使用方法的详解:创建 UpdateWrapper 实例:使用 new UpdateWrapper<实体类>() 创建 UpdateWrapper 对象,并指定实体类作为泛型参数。例如,对于名为 User 的实体类,可以使用 UpdateWrapper<User> updateWrapper = new UpdateWrapper<>(); 来创建 UpdateWrapper 实例。设置更新条件:通过 UpdateWrapper 的方法链,可以设置各种更新条件,如等于、不等于、大于、小于、模糊匹配等。例如,可以使用 updateWrapper.eq("name", "John") 设置 name 字段等于 "John" 的更新条件。添加更新字段:通过 UpdateWrapper 的方法链,可以添加要更新的字段和对应的值。例如,可以使用 updateWrapper.set("age", 20) 设置 age 字段的值为 20。更新操作:将 UpdateWrapper 对象传递给 MyBatis-Plus 提供的相应的 update 方法,如 update、updateBatchById、updateBatch 等,以执行实际的更新操作。UpdateWrapper 提供了便捷的更新条件构造方式,可以灵活地满足各种复杂的更新需求。它与 MyBatis-Plus 框架无缝集成,提供了丰富的更新操作方法
  • [技术干货] QueryWrapper 的一些主要特性和使用方法
    QueryWrapper 是 MyBatis-Plus 框架中的一个查询条件构造器,用于构建 SQL 查询语句的查询条件。通过 QueryWrapper,你可以使用链式编程风格来构建查询条件,并将其传递给 MyBatis-Plus 提供的各种查询方法,如 selectOne、selectList、selectPage 等,以实现灵活的查询操作。以下是 QueryWrapper 的一些主要特性和使用方法的详解:创建 QueryWrapper 实例:使用 new QueryWrapper<实体类>() 创建 QueryWrapper 对象,并指定实体类作为泛型参数。例如,对于名为 User 的实体类,可以使用 QueryWrapper<User> queryWrapper = new QueryWrapper<>(); 来创建 QueryWrapper 实例。设置查询条件:通过 QueryWrapper 的方法链,可以设置各种查询条件,如等于、不等于、大于、小于、模糊匹配等。例如,可以使用 queryWrapper.eq("name", "John") 设置 name 字段等于 "John" 的查询条件。添加查询条件:通过 QueryWrapper 的方法链,可以添加多个查询条件,它们之间的关系默认为 AND 关系。例如,可以使用 queryWrapper.eq("name", "John").ge("age", 18) 添加一个 name 字段等于 "John" 且 age 字段大于等于 18 的查询条件。排序查询结果:可以使用 QueryWrapper 提供的 orderByAsc 和 orderByDesc 方法来对查询结果进行升序或降序排序。例如,可以使用 queryWrapper.orderByAsc("age") 对 age 字段进行升序排序。分页查询:通过 QueryWrapper 的 page 方法,可以指定查询的起始页码和每页的记录数,以实现分页查询功能。查询结果转换:通过 QueryWrapper 的 select 方法,可以指定查询结果返回的字段,以及对结果进行实体类转换等操作。执行查询:最后,将 QueryWrapper 对象传递给 MyBatis-Plus 提供的相应查询方法,如 selectOne、selectList、selectPage 等,以执行实际的查询操作。QueryWrapper 提供了便捷的查询条件构造方式,可以灵活地满足各种复杂的查询需求。它与 MyBatis-Plus 框架无缝集成,提供了丰富的查询和操作方法,以简化开发过程,提高开发效率。
  • [技术干货] PageHelper用法详解
    PageHelper 是一个用于实现分页功能的 MyBatis 插件。它提供了一组方便的方法和注解,帮助开发人员简化分页查询的操作。以下是 PageHelper 的一些主要特性和使用方法的详解:导入依赖:将 PageHelper 作为 Maven 或 Gradle 依赖引入项目中。配置插件:在 MyBatis 的配置文件中添加 PageHelper 的插件配置,包括指定数据库类型、设置是否支持合理化、设置参数名字规则等。示例配置如下:<!-- MyBatis 配置文件 --> <plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"> <property name="dialect" value="mysql" /> <property name="reasonable" value="true" /> </plugin> </plugins>xml复制代码使用方法:在进行分页查询的方法上添加 @com.github.pagehelper.PageHelper 注解,或者在代码中手动调用 PageHelper.startPage() 方法开始分页。执行查询语句后,使用 PageInfo 类进行结果封装,该类提供了丰富的分页信息和查询结果处理方法。示例代码如下:import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; public class UserMapper { @PageHelper(startPage = 1, pageSize = 10) public List<User> getUsers() { // 查询代码... } } // 在其他类中使用查询方法并获取分页信息 PageHelper.startPage(1, 10); List<User> userList = userMapper.getUsers(); PageInfo<User> pageInfo = new PageInfo<>(userList);PageHelper 提供了灵活且强大的分页功能,可以方便地实现查询结果的分页展示。它支持多种数据库类型,提供了丰富的配置选项,同时还可以与 MyBatis 的其他功能无缝集成。通过使用 PageHelper 插件,开发人员可以轻松地处理分页查询的逻辑,提高开发效率。
  • [技术干货] ${} 和#{}区别
    ${} 和 #{} 是 MyBatis 中用于传递参数的占位符。${} 表示字符替换占位符,它会直接将参数的值替换到 SQL 语句中,相当于拼接字符串。例如:<select id="getUserById" resultType="User"> SELECT * FROM user WHERE id = ${userId} </select>xml复制代码在这个示例中,${userId} 会被实际的 userId 参数值替换,生成的 SQL 语句会直接拼接该值。因此,如果不注意防范,容易导致 SQL 注入攻击。相比之下,#{} 是预编译占位符,它会对参数进行预处理,防止 SQL 注入攻击。例如:<select id="getUserById" resultType="User"> SELECT * FROM user WHERE id = #{userId} </select>xml复制代码在这个示例中,#{userId} 会被预编译为占位符 ?,然后通过 JDBC 的预编译机制传递参数值。MyBatis 会在执行 SQL 语句时将参数值安全地绑定到占位符上,从而避免了 SQL 注入攻击的风险。总的来说,为了保证安全性,推荐使用 #{} 进行参数传递,尽量避免使用 ${} 进行字符替换。使用预编译占位符可以有效防止 SQL 注入等安全问题。
  • [其他] MyBatis-Plus-Join
     ​ 介绍 MyBatis-Plus-Join (opens new window)(简称 MPJ)是一个 MyBatis-Plus (opens new window)的增强工具,在 MyBatis-Plus 的基础上只做增强不做改变,为简化开发、提高效率而生。  #特性 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑 无感引入, 支持MP风格的查询, 您会MP就会MPJ, 无需额外的学习成本 兼容MP的别名、逻辑删除、枚举列、TypeHandle列等特性 支持注解形式一对一、一对多和连表查询形式的一对一和一对多 MPJLambdaWrapper class MpJoinTest {     @Resource     private UserMapper userMapper;      @Test     void joinTest() {         List<UserDTO> list = userMapper.selectJoinList(UserDTO.class,                 new MPJLambdaWrapper<>()                         .selectAll(UserDO.class)                         .select(UserAddressDO::getTel)                         .leftJoin(UserAddressDO.class, UserAddressDO::getUserId,UserDO::getId)                         .eq(UserDO::getId, 2));     } } 对应sql  SELECT      t.id,     t.name,     t.sex,     t.head_img,     t1.tel  FROM      user t      LEFT JOIN user_address t1 ON t1.user_id = t.id  WHERE (     t.id = ?)     左连接   #单条件(等于 = )示例:   .leftJoin(UserAddressDO.class, UserAddressDO::getUserId,UserDO::getId)    对应sql     LEFT JOIN user_address t1 on t1.user_id = user.id   #自定义表别名   .leftJoin(UserAddressDO.class, "addr", UserAddressDO::getUserId,UserDO::getId)    比如需要关联同一张表两次及以上时候就需要自定义别名进行区分   别名使用案例     对应sql     LEFT JOIN user_address addr on addr.user_id = user.id   说明:     第一个参数: 参与连表的实体类class   第二个参数: 连表的ON字段,这个属性必须是第一个参数实体类的属性   第三个参数: 参与连表的ON的另一个实体类属性     #多条件示例   .leftJoin(UserAddressDO.class, on -> on                           .eq(UserAddressDO::getUserId, UserDO::getId)                           .eq(UserAddressDO::getId, UserDO::getId))   //自定义别名   .leftJoin(UserAddressDO.class, "addr", on -> on           .eq(UserAddressDO::getUserId, UserDO::getId)           .eq(UserAddressDO::getId, UserDO::getId))   对应sql     LEFT JOIN user_address t1 ON (t1.user_id = t.id AND t1.id = t.id)     LEFT JOIN user_address addr ON (addr.user_id = t.id AND addr.id = t.id)   ​ 
总条数:43 到第
上滑加载中