依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>1.加载 JDBC 驱动程序 2.创建数据库的连接 3.创建 preparedStatement 4.执⾏ SQL 语句 5.处理结果集 6.关闭 JDBC 对象资源
Class.forName("com.mysql.cj.jdbc.Driver"); //连接 String url = "jdbc:mysql://127.0.0.1:3306/test? useUnicode=true&characterEncoding=utf-8&useSSL=false"; String username = "test"; String password = "test"; //获取连接对象,并连接数据库 Connection connection = DriverManager.getConnection(url,username,password); //获取语句对象 Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("select * from t_test1"); while (resultSet.next()){ System.out.println(resultSet.toString()); } statement.close();每次要加载驱动,连接信息是硬编码 sql 和 java 代码耦合⼀起,改动不易 参数设置缺少灵活性 处理结果集麻烦,不能⾃动映射到实体类 连接资源不能复⽤,资源浪费
mybatis – MyBatis 3 | Introduction
依赖
<dependencies> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.9</version> </dependency> <!-- 使⽤JDBC链接mysql的驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.19</version> </dependency> </dependencies>每个基于 MyBatis 的应⽤都是以⼀个 SqlSessionFactory 的实例为核⼼ SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得 SqlSessionFactoryBuilder 可以从 XML 配置⽂件或⼀个预先配置的 Confifiguration 实例来构 建出 SqlSessionFactory 实例 ⼯⼚设计模式⾥⾯ 需要获取 SqlSession ,⾥⾯提供了在数据库执⾏ SQL 命令所需的所有⽅法 配置 mybatis-confifig.xml.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://127.0.0.1:3306/test2? useUnicode=true&characterEncoding=utf-8&useSSL=false"/> <property name="username" value="test"/> <property name="password" value="test"/> </dataSource> </environment> </environments> <mappers> <mapper resource="mapper/TestMaper.xml"/> </mappers> </configuration>
TestMapper.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.test.dao.TestMapper"> <select id="selectById" resultType="com.test.domain.Test"> select * from t_test_2 where id = #{test_id} </select> </mapper>取 java 对象的某个值,属性名⼤⼩写要⼀致 #{value} : 推荐 , 是 java 的名称 ${value} : 不推荐,存在 sql 注⼊⻛险
public static void main(String [] args) throws IOException { String resouce = "config/mybatis-config.xml"; //读取配置⽂件 InputStream inputStream = Resources.getResourceAsStream(resouce); //构建Session⼯⼚ SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //获取Session try(SqlSession sqlSession = sqlSessionFactory.openSession()){ TestMapper testMapper = sqlSession.getMapper(TestMapper.class); Test test= testMapper.selectById(1); List<Test > testList = testMapper.selectList(); System.out.println(testList .toString()); } }
/** * 查询列表 * @return */ @Select("select * from t_test2") List<Test> selectList();
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </dependency>
log4j.rootLogger=ERROR, stdout log4j.logger.com.test=DEBUG log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
<select id="selectByPointAndTitleLike" resultType="com.test.domain.Test"> select * from t_test2 where point=#{point} and title like concat('%', # {title},'%') </select>
<!--下划线⾃动映射驼峰字段--> <settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings>
JDBC Type Java Type CHAR String VARCHAR String LONGVARCHAR String NUMERIC java.math.BigDecimal DECIMAL java.math.BigDecimal BIT boolean BOOLEAN boolean TINYINT byte SMALLINT short INTEGER INTEGER INTEGER int BIGINT long REAL float FLOAT double DOUBLE double BINARY byte[] VARBINARY byte[] LONGVARBINARY byte[] DATE java.sql.Date TIME java.sql.Time TIMESTAMP java.sql.Timestamp CLOB Clob BLOB Blob ARRAY Array DISTINCT mapping of underlying type STRUCT Struct REF Ref DATALINK java.net.URL
<insert id="add" parameterType="com.test.domain.Test"> INSERT INTO `t_test2` ( `title`, `summary`, `cover_img`, `price`, `create_time`, `point`) VALUES (#{title,jdbcType=VARCHAR},#{summary,jdbcType=VARCHAR},# {coverImg,jdbcType=VARCHAR},#{price,jdbcType=INTEGER}, #{createTime,jdbcType=TIMESTAMP},#{point,jdbcType=DOUBLE}); </insert>
<insert id="add" parameterType="com.test.domain.Test" useGeneratedKeys="true" keyProperty="id" keyColumn="id" > INSERT INTO `t_test2` ( `title`, `summary`, `cover_img`, `price`, `create_time`, `point`) VALUES (#{title,jdbcType=VARCHAR},#{summary,jdbcType=VARCHAR},# {coverImg,jdbcType=VARCHAR},#{price,jdbcType=INTEGER}, #{createTime,jdbcType=TIMESTAMP},#{point,jdbcType=DOUBLE}); </insert> //新增⼀条记录 Test test= new Test(); test.setTitle("testtesttest"); test.setCoverImg("xdclass.net/aaa.png"); test.setPoint(9.4); test.setCreateTime(new Date()); test.setPrice(9900); test.setSummary("test for test"); int rows = testMapper.add(test); System.out.println(rows); System.out.println(test.toString());
包含以下属性: collection:必填,值为要迭代循环的集合类型,情况有多种 ⼊参是List类型的时候,collection属性值为list ⼊参是Map类型的时候,collection 属性值为map的key值 item:每⼀个元素进⾏迭代时的别名 index:索引的属性名,在集合数组情况下值为当前索引值,当迭代对象是map时,这个值是 map的key open:整个循环内容的开头字符串 close:整个循环内容的结尾字符串 separator: 每次循环的分隔符 <!--批量插⼊--> <insert id="addBatch" parameterType="com.test.domain.Test" useGeneratedKeys="true" keyProperty="id" keyColumn="id" > INSERT INTO `t_test2` ( `title`, `summary`, `cover_img`, `price`, `create_time`, `point`) VALUES <foreach collection="list" item="test" separator=","> (#{test.title,jdbcType=VARCHAR},#{test.summary,jdbcType=VARCHAR},# {test.coverImg,jdbcType=VARCHAR}, #{test.price,jdbcType=INTEGER}, #{test.createTime,jdbcType=TIMESTAMP},#{test.point,jdbcType=DOUBLE}) <foreach/>
<update id="updateTest" parameterType="com.test.domain.Test"> UPDATE t_test2 set title = #{title,jdbcType=VARCHAR}, summary = #{summary,jdbcType=VARCHAR}, cover_img = #{coverImg,jdbcType=VARCHAR}, price = #{price,jdbcType=INTEGER}, c_id = #{cId,jdbcType=INTEGER}, point = #{point,jdbcType=INTEGER}, update_time = now() WHERE id = #{id} </update>存在其他不想被更新的字段却置为 null 或者默认值了
//当前字段符合条件才更新这个字段的值 <if test='title != null and id == 1'> title = #{title}, </if> <if test="title!=null"> title = #{title}, </if>
<update id="updateTestSelective" parameterType="com.test.domain.Test"> update t_test2 <trim prefix="set" suffixOverrides=","> <if test="title != null "> title = #{title,jdbcType=VARCHAR}, </if> <if test="summary != null "> summary = # {summary,jdbcType=VARCHAR},</if> <if test="coverImg != null "> cover_img = # {coverImg,jdbcType=VARCHAR},</if> <if test="price != 0 "> price = #{price,jdbcType=INTEGER}, </if> <if test="createTime !=null "> create_time = # {createTime,jdbcType=TIMESTAMP},</if> <!-- 特别注意: ⼀定要看pojo类⾥⾯的是基本数据类型,还是包装数据类型--> <if test="point != null "> point = #{point,jdbcType=DOUBLE}, </if> </trim> where id = #{id} </update>
<delete id="deleteByCreateTimeAndPrice" parameterType="java.util.Map"> delete from test where create_time <![CDATA[ > ]]> #{createTime} and price <![CDATA[ >= ]]> #{price} </delete>⼤于等于 <![CDATA[ >= ]]> ⼩于等于 <![CDATA[ <= ]]>
<typeAlias type="com.test.domain.Test" alias="Test"/> <!--<select id="selectById" parameterType="java.lang.Integer" resultType="com.test.domain.Test">--> <select id="selectById" parameterType="java.lang.Integer" resultType="Test"> select * from t_test2 where id = #{test_id,jdbcType=INTEGER} </select> <typeAliases> <!--<typeAlias type="com.test.domain.Test" alias="Test"/>--> <package name="com.test.domain"/> </typeAliases>
<sql id="base_test_field"> id,title,summary,cover_img </sql> <select id="selectById" parameterType="java.lang.Integer" resultType="Test"> select <include refid="base_test_field"/> from t_test2 where id = # {test_id,jdbcType=INTEGER} </select> <select id="selectListByXML" resultType="Test"> select <include refid="base_test_field"/> from t_test2 </select>
<resultMap id="TestResultMap" type="Test"> <!-- id 指定查询列的唯⼀标示 column 数据库字段的名称 property pojo类的名称 --> <id column="id" property="id" jdbcType="INTEGER" /> <result column="test_tile" property="title" jdbcType="VARCHAR" /> <result column="summary" property="summary" jdbcType="VARCHAR" /> <result column="cover_img" property="coverImg" jdbcType="VARCHAR" /> </resultMap> <select id="selectBaseFieldByIdWithResultMap" resultMap="TestResultMap"> select id , title as test_tile, summary, cover_img from t_test2 where id = # {test_id} </select>
<resultMap id="orderResultMap" type="Order"> <id column="id" property="id"/> <result column="user_id" property="userId"/> <result column="out_trade_no" property="outTradeNo"/> <result column="create_time" property="createTime"/> <result column="state" property="state"/> <result column="total_fee" property="totalFee"/> <result column="test_id" property="testId"/> <result column="test_title" property="testTitle"/> <result column="test_img" property="testImg"/> <!-- association 配置属性⼀对⼀ property 对应videoOrder⾥⾯的user属性名 javaType 这个属性的类型 --> <association property="user" javaType="User"> <id property="id" column="user_id"/> <result property="name" column="name"/> <result property="headImg" column="head_img"/> <result property="createTime" column="create_time"/> <result property="phone" column="phone"/> </association> </resultMap> <!--⼀对⼀管理查询订单, 订单内部包含⽤户属性--> <select id="queryVideoOrderList" resultMap="OrderResultMap"> select o.id id, o.user_id , o.out_trade_no, o.create_time, o.state, o.total_fee, o.test_id, o.test_title, o.test_img, u.name, u.head_img, u.create_time, u.phone from order o left join user u on o.user_id = u.id </select>
// resultmap association关联查询 OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class); List<Order> orderList = orderMapper.queryVideoOrderList(); System.out.println(orderList.toString());
<resultMap id="UserOrderResultMap" type="User"> <id property="id" column="id"/> <result property="name" column="name"/> <result property="headImg" column="head_img"/> <result property="createTime" column="create_time"/> <result property="phone" column="phone"/> <!-- property 填写pojo类中集合类属性的名称 ofType 集合⾥⾯的pojo对象 --> <collection property="orderList" ofType="Order"> <!--配置主键,管理order的唯⼀标识--> <id column="order_id" property="id"/> <result column="user_id" property="userId"/> <result column="out_trade_no" property="outTradeNo"/> <result column="create_time" property="createTime"/> <result column="state" property="state"/> <result column="total_fee" property="totalFee"/> <result column="video_id" property="videoId"/> <result column="video_title" property="videoTitle"/> <result column="video_img" property="videoImg"/> </collection> </resultMap> <select id="queryUserOrder" resultMap="UserOrderResultMap"> select u.id, u.name, u.head_img, u.create_time, u.phone, o.id order_id, o.out_trade_no, o.user_id, o.create_time, o.state, o.total_fee, o.test_id, o.test_title, o.test_img from user u left join order o on u.id = o.user_id </select>
// resultmap association关联查询 OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class); //resultmap collection测试 List<User> userList = orderMapper.queryUserOrder(); System.out.println(userList.toString());association 映射的是⼀个 pojo 类,处理⼀对⼀的关联关系。 collection 映射的⼀个集合列表,处理的是⼀对多的关联关系。
<!-- column不做限制,可以为任意表的字段,⽽property须为type 定义的pojo属性--> <resultMap id="唯⼀的标识" type="映射的pojo对象"> <id column="表的主键字段,或查询语句中的别名字段" jdbcType="字段类型" property="映射 pojo对象的主键属性" /> <result column="表的⼀个字段" jdbcType="字段类型" property="映射到pojo对象的⼀个属 性"/> <association property="pojo的⼀个对象属性" javaType="pojo关联的pojo对象"> <id column="关联pojo对象对应表的主键字段" jdbcType="字段类型" property="关联pojo 对象的属性"/> <result column="表的字段" jdbcType="字段类型" property="关联pojo对象的属性"/> </association> <!-- 集合中的property 需要为oftype定义的pojo对象的属性--> <collection property="pojo的集合属性名称" ofType="集合中单个的pojo对象类型"> <id column="集合中pojo对象对应在表的主键字段" jdbcType="字段类型" property="集合 中pojo对象的主键属性" /> <result column="任意表的字段" jdbcType="字段类型" property="集合中的pojo对象的属 性" /> </collection> </resultMap>
<!--开启mapper的namespace下的⼆级缓存--> <!-- eviction:代表的是缓存回收策略,常⻅下⾯两种。 (1) LRU,最近最少使⽤的,⼀处最⻓时间不⽤的对象 (2) FIFO,先进先出,按对象进⼊缓存的顺序来移除他们 flushInterval:刷新间隔时间,单位为毫秒,这⾥配置的是100秒刷新,如果不配置 它,当SQL被执⾏的时候才会去刷新缓存。 size:引⽤数⽬,代表缓存最多可以存储多少个对象,设置过⼤会导致内存溢出 readOnly:只读,缓存数据只能读取⽽不能修改,默认值是false --> <cache eviction="LRU" flushInterval="100000" readOnly="true" size="1024"/>
全局配置: <settings> <!--这个配置使全局的映射器(⼆级缓存)启⽤或禁⽤缓存,全局总开关,这⾥关闭,mapper中开启 了也没⽤--> <setting name="cacheEnabled" value="true" /> </settings>如果需要控制全局 mapper ⾥⾯某个⽅法不使⽤缓存,可以配置 useCache="false"
<select id="selectById" parameterType="java.lang.Integer" resultType="Test" useCache="false"> select <include refid="base_test_field"/> from t_test2 where id = # {test_id,jdbcType=INTEGER} </select>优先查询⼆级缓存 - 》查询⼀级缓存 - 》数据库 什么是懒加载: 按需加载,先从单表查询,需要时再从关联表去关联查询,能⼤⼤提⾼数据库性能 , 并不是所有场景下使⽤懒加载都能提⾼效率 Mybatis 懒加载: resultMap ⾥⾯的 association 、 collection 有延迟加载功能
<!--全局参数设置--> <settings> <!--延迟加载总开关--> <setting name="lazyLoadingEnabled" value="true"/> <!--将aggressiveLazyLoading设置为false表示按需加载,默认为true--> <setting name="aggressiveLazyLoading" value="false"/> </settings>
<resultMap id="TestOrderResultMapLazy" type="TestOrder"> <id column="id" property="id"/> <result column="user_id" property="userId"/> <result column="out_trade_no" property="outTradeNo"/> <result column="create_time" property="createTime"/> <result column="state" property="state"/> <result column="total_fee" property="totalFee"/> <result column="test_id" property="testId"/> <result column="test_title" property="testTitle"/> <result column="test_img" property="testImg"/> <!-- select: 指定延迟加载需要执⾏的statement id column: 和select查询关联的字段 --> <association property="user" javaType="User" column="user_id" select="findUserByUserId"/> </resultMap> <!--⼀对⼀管理查询订单, 订单内部包含⽤户属性 懒加载--> <select id="queryTestOrderListLazy" resultMap="TestOrderResultMapLazy"> select o.id id, o.user_id , o.out_trade_no, o.create_time, o.state, o.total_fee, o.test_id, o.test_title, o.test_img from test_order o </select> <select id="findUserByUserId" resultType="User"> select * from user where id=#{id} </select>dubug 模式测试懒加载不准确,可以直接 run
<environment id="development"> <!-- mybatis使⽤jdbc事务管理⽅式 --> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://127.0.0.1:3306/test? useUnicode=true&characterEncoding=utf-8&useSSL=false"/> <property name="username" value="test"/> <property name="password" value="test"/> </dataSource> </environment>事务⼯⼚ TransactionFactory 的两个实现类 JdbcTransactionFactory->JdbcTransaction ManagedTransactionFactory->ManagedTransaction 注意:如果不是 web 程序,然后使⽤的事务管理形式是 MANAGED, 那么将没有事务管理功能