1、创建项目并添加依赖、连接数据库,编写mybatis的配置文件
项目结构如下
所需依赖如下(创建的是聚合工程,请根据自己的是实际情况选择合适的版本)
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<mybatis.version>3.5.6</mybatis.version>
<mysql.version>8.0.30</mysql.version>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.18.26</lombok.version>
</properties>
<dependencyManagement>
<dependencies>
<!--mybatis核心依赖-->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!--mysql驱动-->
<!-- https://mvnrepository.com/artifact/com.mysql/mysql-connector-j -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!--单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!--日志-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
核心配置文件mybatis-config.xml文件如下(当然你可以给他起别的名字,官网上写的是mybatis-config.xml)
在mappers标签中采用的是自动扫描的方式,即会扫描所有com.ls.dao下的xml文件或dao接口
<?xml version="1.0" encoding="GBK"?>
<!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/mybatis?useUnicode=true"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- <mapper class="com.ls.dao.BookDao"></mapper>-->
<package name="com.ls.dao"/>
</mappers>
</configuration>
定义日志输出内容
# 定义输出级别为 debug,输出名称为 stdout
log4j.rootLogger=debug,stdout
# 定义 stdout 的输出采用哪个类来执行
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
# 定义 stdout 的输出类型的样式布局
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# 定义 stdout 样式布局的消息格式
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
创建数据库并在idea中连接
CREATE TABLE `book` (
`book_id` int NOT NULL AUTO_INCREMENT,
`book_name` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
`book_author` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`book_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
2、创建工具类MybatisUtil
前面的mybatis简单入门我们已经知道该框架需要通过流加载配置文件mybatis-config.xml创建工厂SqlSessionFactory并使用工厂生产的对象的openSession(打开一个新的session对象,而且每次使用都是打开一个新的session,假如连续使用多次,则获得的session不是同一个对象,并且使用完需要调用close方法关闭session)获取session,这些都是固定的,我们的目的就是获得session对象,所以直接封装成一工具类,让项目启动时就进行加载以便使用。
/**
* date: 2023/2/25
*
* @author Arc
*/
package com.ls.util;
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.InputStream;
public class MybatisUtil {
static SqlSessionFactory sqlSessionFactory = null;
static {
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获得SqlSession
*
* @return
*/
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession();
}
}
3、创建实体类和数据持久层接口、配置映射文件
/**
* date: 2023/2/25
*
* @author Arc
*/
package com.ls.model;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
@Data
@Accessors(chain = true)
public class Book {
private int bookId;
private String bookName;
private String bookAuthor;
private Date createTime;
private Date updateTime;
}
在dao中已经写好了增删改查的一些方法方便直接复制调试。
package com.ls.dao;
import com.ls.model.Book;
import java.util.List;
public interface BookDao {
/**
* 添加图书
* @param book
* @return
*/
int add(Book book);
/**
* 根据id查找
* @param bookId
* @return
*/
Book findById(Integer bookId);
/**
* 查询所有
* @return
*/
List<Book> findAll();
/**
* 根据名字查询所有书籍
* @param bookName
* @return
*/
List<Book> findByName(String bookName);
/**
* 根据id删除
* @param bookId
* @return
*/
int deleteById(int bookId);
/**
* 根据id修改
* @param book
* @return
*/
int updateById(Book book);
}
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace:全路径接口名称
id:接口中对应的方法名
parameterType:方法的入参类型
(#{bookName}:取值
-->
<mapper namespace="com.ls.dao.BookDao">
<insert id="add" parameterType="com.ls.model.Book">
-- 返回自增长的主键
-- keyProperty的值应该是实体类对应的名字
<selectKey keyProperty="bookId" order="AFTER" resultType="int">
select last_insert_id()
</selectKey>
insert into book (book_name,book_author,create_time,update_time)
values (#{bookName},#{bookAuthor},#{createTime},#{updateTime})
</insert>
<select id="findById" parameterType="java.lang.Integer" resultType="com.ls.model.Book">
select book_id bookId,book_name bookName,book_author bookAuthor,create_time createTime,update_time updateTime
from book
where book_id=#{bookId}
</select>
<select id="findAll" resultType="com.ls.model.Book">
select book_id bookId,book_name bookName,book_author bookAuthor,create_time createTime,update_time updateTime
from book
</select>
<select id="findByName" parameterType="java.lang.String" resultType="com.ls.model.Book">
select book_id bookId,book_name bookName,book_author bookAuthor,create_time createTime,update_time updateTime
from book
-- 拼接字符串容易造成sql注入,在这里$相当于+
-- where book_name like '%${bookName}%'
where book_name like concat('%',#{bookName},'%')
</select>
<delete id="deleteById" parameterType="java.lang.Integer">
delete from book where book_id=#{bookId}
</delete>
<update id="updateById" parameterType="com.ls.model.Book">
update book set book_name = #{bookName},book_author= #{bookAuthor},update_time = now()
where book_id = #{bookId}
</update>
</mapper>
4、编写mapper映射文件和service层
在mapper代理开发中要求mapper.xml文件的名字要和dao层它对应接口的名字相同,且把二者放到同一目录下,但是我们一般会把配置文件都放到resource目录下,所以我们在resource目录下创建与dao接口对应的目录,注意在创建时要使用 “ / ” 来代替 “ . ” ,否则目录不会分层。
/**
* date: 2023/2/25
*
* @author Arc
*/
package com.ls.service;
import com.ls.dao.BookDao;
import com.ls.model.Book;
import com.ls.util.MybatisUtil;
import org.apache.ibatis.session.SqlSession;
import java.util.Date;
import java.util.List;
public class BookService {
public static void main(String[] args) {
// testInsert();
testFindAll();
// testFindById();
// testFindByName();
// testDeleteById();
// testUpdateById();
}
/**
* 测试添加
*/
public static void testInsert() {
SqlSession sqlSession = null;
try {
sqlSession = MybatisUtil.getSqlSession();
//获得BookDao对象
BookDao bookDao = sqlSession.getMapper(BookDao.class);
Book book = new Book()
.setBookName("bookname").setBookAuthor("author").setCreateTime(new Date()).setUpdateTime(new Date());
int result = bookDao.add(book);
System.out.println(result > 0 ? "成功" : "失败");
sqlSession.commit();
System.out.println(book);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
/**
* 测试查找所有
*/
public static void testFindAll() {
SqlSession sqlSession = null;
try {
sqlSession = MybatisUtil.getSqlSession();
//获得BookDao对象
BookDao bookDao = sqlSession.getMapper(BookDao.class);
List<Book> books = bookDao.findAll();
for (Book book1 : books) {
System.out.println(book1);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
/**
* 测试根据id查找
*/
public static void testFindById() {
SqlSession sqlSession = null;
try {
sqlSession = MybatisUtil.getSqlSession();
//获得BookDao对象
BookDao bookDao = sqlSession.getMapper(BookDao.class);
Book book = bookDao.findById(2);
System.out.println(book);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
/**
* 测试根据书名进行模糊查询
*/
public static void testFindByName() {
SqlSession sqlSession = null;
try {
sqlSession = MybatisUtil.getSqlSession();
//获得BookDao对象
BookDao bookDao = sqlSession.getMapper(BookDao.class);
List<Book> books = bookDao.findByName("my");
for (Book book : books) {
System.out.println(book);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
/**
* 测试根据Id删除
*/
public static void testDeleteById() {
SqlSession sqlSession = null;
try {
sqlSession = MybatisUtil.getSqlSession();
//获得BookDao对象
BookDao bookDao = sqlSession.getMapper(BookDao.class);
int result = bookDao.deleteById(1);
System.out.println(result>0?"成功":"没有找到对应数据");
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
public static void testUpdateById() {
SqlSession sqlSession = null;
try {
sqlSession = MybatisUtil.getSqlSession();
//获得BookDao对象
BookDao bookDao = sqlSession.getMapper(BookDao.class);
Book book = new Book()
.setBookId(2).setBookAuthor("junmenmghbai").setBookName("消愁是怎样炼成的");
int result = bookDao.updateById(book);
sqlSession.commit();
System.out.println(result>0?"更新成功":"没有找到对应数据");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
}
5、一些细节
模糊查询的字符串拼接
在dao层中有一个findByName方法,参数是String类型的书名,要求返回所有含有该参数的Book,即模糊查询
/**
* 根据名字查询所有书籍
* @param bookName
* @return
*/
List<Book> findByName(String bookName);
我们知道在sql语句中可以用%来表示任意个字符,所以我们可以使用 "$" 表示拼接字符串,等同于字符串拼接中的 "+"
<select id="findByName" parameterType="java.lang.String" resultType="com.ls.model.Book">
select book_id bookId,book_name bookName,book_author bookAuthor,create_time createTime,update_time updateTime
from book
where book_name like '%${bookName}%'
</select>
但是使用字符串拼接如果用户传参不规范就会产生sql注入的问题,所以我们可以使用内置函数concat()将要取的值与 "%" 拼接起来。
<select id="findByName" parameterType="java.lang.String" resultType="com.ls.model.Book">
select book_id bookId,book_name bookName,book_author bookAuthor,create_time createTime,update_time updateTime
from book
where book_name like concat('%',#{bookName},'%')
</select>
⬇️两种sql经过编译后
#{ }和$
首先需要了解两个符号的作用 :#{}是一个参数占位符,对于String类型会自动加上"",其他类型不加。由于Mybatis采用预编译,其后的参数不会再进行SQL编译,所以一定程度上防止SQL注入。${}是一个简单的String替换,字符串是什么,解析就是什么。
为什么拼接可能会造成sql注入:假如前端传一个bookName值为“java”,对于 where book_name like #{bookName},对应的sql语句就是 where book_name like "java" ;对于 where book_name like ${bookName},对应的sql语句则是where book_name like bookName。这种情况,当用户传参为bookName && 1=1 的时候,就会产生难以预计的后果。
返回自增长主键
如果往某张表中插入一条数据记录,而该表的主键又是自增长的设置,那么在执行 insert 语句 时,我们一般不会对主键列做操作,主键列会自动生成并插入到表中,但是我们可能需要根据主键再去执行相关的修改或者删除操作。
如果表的主键是自增长设置,那么 mysql 在执行 insert 插入提交之前,会自动生成一个自增长主键,并插入到主键列上。获取自增长的主键列的值,可以通过 mysql 的提供的函数 last_insert_id()可以获取到该值,但是此函数的执行必须要在 insert 语句执行之后才可以,所以在 MyBatis 中如果想要获取刚插入的子增长主键记录,则在 mapper.xml 配置文件中,使用如下配置。
这里注意 keyProperty 的值应该是对应POJO类的属性名,即实体名。
<insert id="add" parameterType="com.ls.model.Book">
-- 返回自增长的主键
<selectKey keyProperty="bookId" order="AFTER" resultType="int">
select last_insert_id()
</selectKey>
insert into book (book_name,book_author,create_time,update_time)
values (#{bookName},#{bookAuthor},#{createTime},#{updateTime})
</insert>
⬇️插入成功后返回bookId=9
标签:Mapper,name,bookName,代理,BookDao,sqlSession,book,mybatis02,id From: https://www.cnblogs.com/purearc/p/17195977.html