mybatis学习笔记(day1)
为啥不用JDBC?
首先我们知道jdbc的步骤是:
- 加载数据库驱动
- 创建并获取数据库链接
- 创建jdbc statement对象
- 设置sql语句
- 设置sql语句中的参数(使用preparedStatement)
- 通过statement执行sql并获取结果
- 对sql执行结果进行解析处理
- 释放资源(resultSet、preparedstatement、connection)
我们可以看出,我们频繁的对数据库进行连接和关闭操作(当我们打开datagrip的时候,也要等一下数据库才出来),这很不效率。
设想:使用数据库连接池管理数据库连接
什么是数据库连接池?
数据库连接池是一个存储已经建立的数据库连接并使其可以重复使用的技术,可以减少程序每次建立数据库连接所花费的时间。
使用数据库连接池可以将已经建立的连接保存在连接池中,当有新的数据请求到来时,可以从连接池中获取已创建的空闲连接来使用,从而避免了频繁创建和释放数据库连接的操作,提高了系统的性能,减少了系统的开销。
将sql直接编入java语言中,其实非常不安全而且给维护造成很大影响。
设想:将sql语句配置在xml文件中,即使sql编号,不需要对java代码进行重新编译,直接修改xml文件就好
向preparedStatement中设置参数,对占位符号位置和设置参数值,硬编码在java代码中,不利于系统维护。
设想:将sql语句及占位符号和参数全部配置在xml中。
从resultSet中遍历结果集数据时,存在硬编码,将获取表的字段进行硬编码,不利于系统维护。
设想:将查询的结果集,自动映射成java对象。
参考代码
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 com.iot.mybatis.jdbc;
import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException;
public class JdbcTest { public static void main(String[] args) { Connection connection = null; PreparedStatement preparedStatement = null; ResultSet resultSet = null;
try { Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://120.25.162.238:3306/mybatis001?characterEncoding=utf-8", "root", "123"); String sql = "select * from user where username = ?"; preparedStatement = connection.prepareStatement(sql); preparedStatement.setString(1, "王五"); resultSet = preparedStatement.executeQuery(); while(resultSet.next()){ System.out.println(resultSet.getString("id")+" "+resultSet.getString("username")); } } catch (Exception e) { e.printStackTrace(); }finally{ if(resultSet!=null){ try { resultSet.close(); } catch (SQLException e) { e.printStackTrace(); } } if(preparedStatement!=null){ try { preparedStatement.close(); } catch (SQLException e) { e.printStackTrace(); } } if(connection!=null){ try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } }
}
}
}
|
mybatis介绍
mybatis是一个持久层的框架,是apache下的顶级项目。
mybatis托管到goolecode下,再后来托管到github下(https://github.com/mybatis/mybatis-3/releases)。
mybatis让程序将主要精力放在sql上,通过mybatis提供的映射方式,自由灵活生成(半自动化,大部分需要程序员编写sql)满足需要sql语句。
mybatis可以将向 preparedStatement中的输入参数自动进行输入映射,将查询结果集灵活映射成java对象。(输出映射)
框架原理
mybatis框架执行过程
1、配置mybatis的配置文件,SqlMapConfig.xml(名称不固定)
2、通过配置文件,加载mybatis运行环境,创建SqlSessionFactory会话工厂(SqlSessionFactory在实际使用时按单例方式)
3、通过SqlSessionFactory创建SqlSession。SqlSession是一个面向用户接口(提供操作数据库方法),实现对象是线程不安全的,建议sqlSession应用场合在方法体内。
4、调用sqlSession的方法去操作数据。如果需要提交事务,需要执行SqlSession的commit()方法。
5、释放资源,关闭SqlSession
mybatis开发dao的方法
1.原始dao 的方法
- 需要程序员编写dao接口和实现类
- 需要在dao实现类中注入一个SqlSessionFactory工厂
2.mapper代理开发方法(建议使用)
只需要程序员编写mapper接口(就是dao接口)。 程序员在编写mapper.xml(映射文件)和mapper.java需要遵循一个开发规范:
- mapper.xml中namespace就是mapper.java的类全路径。
- mapper.xml中statement的id和mapper.java中方法名一致。
- mapper.xml中statement的parameterType指定输入参数的类型和mapper.java的方法输入参数类型一致
- mapper.xml中statement的resultType指定输出结果的类型和mapper.java的方法返回值类型一致。
SqlMapConfig.xml配置文件:可以配置properties属性、别名、mapper加载。
输入映射和输出映射
- 输入映射:
- parameterType:指定输入参数类型可以简单类型、pojo、hashmap。
- 对于综合查询,建议parameterType使用包装的pojo,有利于系统扩展。
- 输出映射:
- resultType:查询到的列名和resultType指定的pojo的属性名一致,才能映射成功。
- reusltMap:可以通过resultMap 完成一些高级映射。如果查询到的列名和映射的pojo的属性名不一致时,通过resultMap设置列名和属性名之间的对应关系(映射关系)。可以完成映射。
- 高级映射: 将关联查询的列映射到一个pojo属性中。(一对一) 将关联查询的列映射到一个List中。(一对多)
动态sql
- 动态sql:(重点)
- if判断(掌握)
- where
- foreach
- sql片段(掌握)
代码(我是用maven来加载jar包的)
一些jar包(有什么功能不知道 默认导入的 核心jar包是mybatis sql-driver 我的mysql是8.0.32版本的 junit 单元测试)
新建项目的时候选的是maven 默认格式 可以自己把config写出来 也可以在mian下面的文件resource中写 但是要注意 写了config要将该文件设置为资源文件 这个是必须的 普通文件程序不会去看
MybatisFirst 是测试用的 po文件夹里写的是类 数据库字段是什么就写什么
sqlmap下的User.xml
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
| <?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="test">
<select id="findUserById" parameterType="int" resultType="po.User"> SELECT * FROM users.user WHERE userId =#{value} </select>
<select id="findUserByName" parameterType="java.lang.String" resultType="po.User"> SELECT * FROM users.user WHERE username LIKE '%${value}%' </select>
</mapper>
|
SqlMapConfig.xml
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
| <?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://localhost:3306/users?characterEncoding=utf-8" /> <property name="username" value="root" /> <property name="password" value="root" /> </dataSource> </environment> </environments> <mappers> <mapper resource="sqlmap/User.xml"/> </mappers>
</configuration>
|
原因现在还未知,可能和映射有关 涉及到bean的知识?
log4j.properties
1 2 3 4 5 6 7
| log4j.rootLogger=DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
|
first文件的MybatisFirst
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
| package first;
import org.junit.jupiter.api.Test; import po.User; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException; import java.io.InputStream; import java.util.List;
public class MybatisFirst {
@Test public void findUserByIdTest() throws IOException{ String resource = "SqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = sqlSession.selectOne("test.findUserById", 1);
System.out.println(user);
sqlSession.close();
}
@Test public void findUserByNameTest() throws IOException { String resource = "SqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder() .build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession(); List<User> list = sqlSession.selectList("test.findUserByName", "小明"); System.out.println(list); sqlSession.close();
}
}
|
po文件的User
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
| package po;
import java.util.Date;
public class User { private int id; private String username; private String sex; private Date birthday; private String address;
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getSex() { return sex; }
public void setSex(String sex) { this.sex = sex; }
public Date getBirthday() { return birthday; }
public void setBirthday(Date birthday) { this.birthday = birthday; }
public String getAddress() { return address; }
public void setAddress(String address) { this.address = address; }
@Override public String toString() { return "User [id=" + id + ", username=" + username + ", sex=" + sex + ", birthday=" + birthday + ", address=" + address + "]"; } }
|
一般出现sql语句输出 和 结果返回 一般是成功了 注意:比较常见的问题是读不到你的Mybatis.xml文件 一定一定要将config文件设置为资源文件
入门程序二
添加、删除、更新用户
将下面的添加到xml中
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
|
<insert id="insertUser" parameterType="com.iot.mybatis.po.User">
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer"> SELECT LAST_INSERT_ID() </selectKey> INSERT INTO user (username,birthday,sex,address)values (#{username},#{birthday},#{sex},#{address})
</insert>
<delete id="deleteUser" parameterType="java.lang.Integer"> delete from user where id=#{id} </delete>
<update id="updateUser" parameterType="com.iot.mybatis.po.User"> update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id} </update>
|
程序代码
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
| @Test public void insertUserTest() throws IOException { String resource = "SqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder() .build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession(); User user = new User(); user.setUsername("王小军"); user.setBirthday(new Date()); user.setSex("1"); user.setAddress("河南郑州");
sqlSession.insert("test.insertUser", user);
sqlSession.commit();
System.out.println(user.getId()); sqlSession.close();
}
@Test public void deleteUserTest() throws IOException { String resource = "SqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder() .build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.delete("test.deleteUser", 29);
sqlSession.commit();
sqlSession.close();
}
@Test public void updateUserTest() throws IOException { String resource = "SqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder() .build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = new User(); user.setId(27); user.setUsername("王大军"); user.setBirthday(new Date()); user.setSex("2"); user.setAddress("河南郑州");
sqlSession.update("test.updateUser", user);
sqlSession.commit();
sqlSession.close();
}
|
本次难点
我们在sql中将主键id设置为自增
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer"> SELECT LAST_INSERT_ID() </selectKey>
|
总结一下
#{}
表示一个占位符号,#{}
接收输入参数,类型可以是简单类型,pojo、hashmap。
如果接收简单类型,#{}
中可以写成value或其它名称。
#{}
接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性…的方式获取对象属性值。
${}
表示一个拼接符号,会引用sql注入,所以**不建议使用${}
**。
${}
接收输入参数,类型可以是简单类型,pojo、hashmap。
如果接收简单类型,${}
中只能写成value。
${}
接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性…的方式获取对象属性值。