Feb 1997

Overtime and overdue


  • Home

  • Tags

  • Categories

  • Archives

  • Search

MyBatis:注解开发

Posted on 2020-04-08

使用注解开发可以完全省略掉XXXMapper.xml文件
UserMapper(接口)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface UserMapper {

@Select("select * from user")
List<User> getUser();

@Select("select * from user where id = #{id}")
User getUserById(@Param("id") int id);

// 与实体类属性保持一致,虽然数据库里的字段是pwd,但是实体类中是password所以#{password}
@Insert("insert into user(id,name,pwd) values (#{id},#{name},#{password})")
int addUser(User user);

@Update("update user set name=#{name},pwd=#{password} where id=#{id}")
int updateUser(User user);
}

Test.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
public class UserMapperTest {
@Test
public void getUserTest() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> user = mapper.getUser();
for (User user1 : user) {
System.out.println(user1);
}
}
@Test
public void getUserByIdTest() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User userById = mapper.getUserById(1);
System.out.println(userById);
}
@Test
public void addUserTest() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.addUser(new User(5,"leo","666"));
sqlSession.commit();
sqlSession.close();
}
@Test
public void updateTest() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.updateUser(new User(1,"xiaoke","666"));
sqlSession.commit();
sqlSession.close();
}
}

注解开发的底层实现是应用反射。
但是这个例子中有个问题,实体类中是password但是数据库字段为pwd,获取数据时,pwd会为null,所以官网上说注解开发只适用于简单场景,如果场景复杂还是建议xml

#与$的区别

#{} 的作用主要是替换预编译语句(PrepareStatement)中的占位符?:

对于 : INSERT INTO user (name) VALUES (#{name}); ==> INSERT INTO user (name) VALUES (?);

${} 符号的作用是直接进行字符串替换:

对于 : INSERT INTO user (name) VALUES (‘${name}’); ==> INSERT INTO user (name) VALUES (‘tianshozhi’);

为了防止SQL注入,建议使用#{}.

关于@Param()注解

  • 基本类型的参数或者String类型,需要加上
  • 引用类型不需加
  • 如果只有一个基本类型的话,可以忽略,但是建议大家都加上
  • 我们在SQL中引用的就是我们这里@Param()中设定的属性名
    例如
    1
    2
    @Select("select * from user where id = #{id}")
    User getUserById(@Param("id") int id);

如果吧@Param改成(“id2”),上面的#{}也要改:

1
2
@Select("select * from user where id = #{id2}")
User getUserById(@Param("id2") int id);

MyBatis:分页

Posted on 2020-04-08

用Limit控制分页

UserMapper.xml:

1
2
3
<select id="getUserByLimit" parameterType="map" resultType="User">
select * from user limit #{startIndex},#{pageSize}
</select>

Test.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Test
public void getUserByLimit() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("startIndex",1);
map.put("pageSize",2);
List<User> userByLimit = mapper.getUserByLimit(map);
for (User user : userByLimit) {
System.out.println(user);
}
sqlSession.close();
}

Java:为什么要get和set方法

Posted on 2020-04-04

在JavaBean中,通常将属性设置为private,然后生成与属性对应的public setXXX(),public getXXX()。那么为什么要这么设计呢?

同一个类 同一个包 同一个包下的子类 不同包下的子类 不同包的非子类
public + + + +
protected + + +
private +

根据上表可以得知,将属性设置为private限制了外界对这个属性的直接访问操作,那么设置对应的get、set方法并设为public的意义就相当于给外界提供了访问的方法,而不是直接将属性暴露。

引用Stackoverflow的答案:

  • Encapsulation of behavior associated with getting or setting the property this allows additional functionality (like validation) to be added more easily later.
  • Hiding the internal representation of the property while exposing a property using an alternative representation.
  • Insulating your public interface from change - allowing the public interface to remain constant while the implementation changes without affecting existing consumers.
  • Controlling the lifetime and memory management (disposal) semantics of the property - particularly important in non-managed memory environments (like C++ or Objective-C).
  • Providing a debugging interception point for when a property changes at runtime - debugging when and where a property changed to a particular value can be quite difficult without this in some languages.
  • Improved interoperability with libraries that are designed to operate against property getter/setters - Mocking, Serialization, and WPF come to mind.
  • Allowing inheritors to change the semantics of how the property behaves and is exposed by overriding the getter/setter methods.
  • Allowing the getter/setter to be passed around as lambda expressions rather than values.
  • Getters and setters can allow different access levels - for example the get may be public, but the set could be protected.

自己目前所理解的:

  • 实现java域变量的封装性和安全性
  • 可以对属性进行验证操作,比如age属性,在set中可以添加验证,如果输入的age小于0则抛出异常
  • 可以在debug的时候用到

Spring Note 8:JavaConfig

Posted on 2020-03-30

The central artifacts in Spring’s new Java-configuration support are @Configuration-annotated classes and @Bean-annotated methods.
The @Bean annotation is used to indicate that a method instantiates, configures, and initializes a new object to be managed by the Spring IoC container. For those familiar with Spring’s<beans/> XML configuration, the @Bean annotation plays the same role as the <bean/> element. You can use @Bean-annotated methods with any Spring @Component. However, they are most often used with @Configuration beans.
Annotating a class with @Configuration indicates that its primary purpose is as a source of bean definitions. Furthermore, @Configuration classes let inter-bean dependencies be defined by calling other @Bean methods in the same class.

使用Config开发可以省略配置文件。
LiuConfig.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 这个也会被Spring容器托管,注册到容器中,因为它本来就是一个@Component
// @Configuration代表这是一个配置类,就和之前的Beans.xml一样
@Configuration
public class LiuConfig {

// 注册一个bean,相当于之前写的一个bean标签
// 方法的名字就相当于bean标签的id属性
// 方法的返回值,就相当于bean标签中的class属性
@Bean
public User user() {
return new User();
}
}

User.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Component
public class User {
@Value("XLIU")
private String name;

@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}

MyTest.java:

1
2
3
4
5
6
7
8
public class MyTest {
public static void main(String[] args) {
// 如果完全使用了配置类方法去做,我们就只能通过AnnotationConfig上下文来获取容器,通过配置类的class对象加载
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(LiuConfig.class);
User user = applicationContext.getBean("user", User.class);
System.out.println(user.getName());
}
}

Spring Note 7: @component

Posted on 2020-03-30

之前提到在xml文件中,一个bean对应一个类,在MyTest中通过获取bean的方法来创建对象。现在介绍一个新的方法,通过使用注解@Component来代替bean。

@Component

使用注解@Component之前,先在xml文件中添加组件:

1
<context:component-scan base-package="com.xliu.pojo"/>

意思为自动扫描路径com.xliu.pojo中所有的@Component。
在pojo类前添加注解@Component意思是告诉Spring,我是一个pojo类,请将我注册到容器中。

使用前

假设我们有一个pojo类User.java:

1
2
3
4
5
6
7
8
9
10
11
public class User {
public String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}

在xml中注册的bean为:

1
2
3
<bean id="user" class="com.xliu.pojo.User">
<property name="name" value="xliu"/>
</bean>

MyTest:

1
2
3
4
5
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) applicationContext.getBean("user");
System.out.println(user.name);
}

输出:

1
xliu

使用后

User.java:

1
2
3
4
5
@Component
public class User {
@Value("xiaokeliu")
public String name;
}

@Component表示组件,注册到Spring中,@Value表示对属性name的赋值
applicationContext.xml:

1
<context:component-scan base-package="com.xliu.pojo"/>

在xml文件中只需要这一行添加组件即可。
MyTest不变,结果输出:

1
xiaokeliu

事实证明,虽然在xml文件中我们没有显式地注册bean,但还是可以通过getBean来创建对象。

衍生注解

@Component 有几个衍生注解,我们在web开发中,会按照MVC三层架构分层

  • dao(@Repository)
  • service(@Service)
  • controller(@Controller)
    功能和@Component一样,都是代表这个类注册到Spring容器中,装配。

XML与注解最佳实践

XML用来管理bean,注解负责完成属性的注入。
那么XML文件中就只有一个一个<bean>,而给属性赋值则通过注解(@Value)实现。

Spring Note 6: beans作用域

Posted on 2020-03-30

When you create a bean definition, you create a recipe for creating actual instances of the class defined by that bean definition. The idea that a bean definition is a recipe is important, because it means that, as with a class, you can create many object instances from a single recipe.

singleton

假设beans.xml:

1
2
3
<bean name="userService" class="Service.UserServiceImpl" scope="singleton">
<property name="userDao" ref="userDao"/>
</bean>

那么通过这个bean创建的对象,地址都是一样的。
MyTest.java:

1
2
3
UserService userService = (UserService) classPathXmlApplicationContext.getBean("userService");
UserService userService2 = (UserService) classPathXmlApplicationContext.getBean("userService");
System.out.println(userService==userService2);

输出:

1
true

prototype

同上,如果把bean中的scope属性的值改为prototype,那么每一次使用这个bean都会创建一个新的对象。
输出:

1
false

总结

  1. singleton在容器中,只被实例化一次,而prototype在容器中,调用几次,就被实例化几次;
  2. 在AppplicationContext容器中,singleton在applicaitonContext.xml加载时就被预先实例化,而prototype必须在调用时才实例化
  3. singleton比prototype消耗性能,在web开发中,推荐使用singleton模式,在app开发中,推荐使用prototype模式。

Spring Note 5:构造函数注入

Posted on 2020-03-29

Recap

之前讨论了setter方法注入,要求在pojo类中要有对应属性的set方法,然后在xml文件中通过标签实现注入。
例如:
User.java:

1
2
3
4
5
6
7
8
9
10
11
public class User {
private String name;

public void setName(String name) {
this.name = name;
}

public void show() {
System.out.println("name="+name);
}
}

beans.xml:

1
<property name="name" value="xliu"/>

构造器注入

除了setter方法注入之外,还有构造器注入,这种方法要求pojo类中有构造函数,不要求set方法。xml文件中使用标签<constructor-arg>。
例如:
User.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class User {
private String name;

public User(String name) {
this.name = name;
}

public String getName() {
return name;
}

public void show() {
System.out.println("name="+name);
}
}

beans.xml:

1
<constructor-arg name="name" value="xliu"/>

其他数据类型

除了基本的数据类型,int,String之类的,还有Map和List类型,其在xml中对应的配置标签如下。
User.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class User {
private String name;
private List<String> dream;
private Map<String,String> score;

public User(String name, List<String> dream, Map<String, String> score) {
this.name = name;
this.dream = dream;
this.score = score;
}

@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", dream=" + dream +
", score=" + score +
'}';
}
}

beans.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<bean id="user" class="com.xliu.pojo.User">
<constructor-arg name="name" value="xliu"/>
<constructor-arg name="dream">
<list>
<value>programmer</value>
<value>travel</value>
</list>
</constructor-arg>
<constructor-arg name="score">
<map>
<entry key="math" value="90"/>
<entry key="science" value="80"/>
</map>
</constructor-arg>
</bean>

输出:

1
User{name='xliu', dream=[programmer, travel], score={math=90, science=80}}

同理,数组对应的标签为<array>,set对应的标签为<set>

Spring Note 4: 第一个程序

Posted on 2020-03-28 Edited on 2020-03-29

配置

Maven依赖

1
2
3
4
5
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>

XML文件模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>

<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>

<!-- more bean definitions go here -->

</beans>

使用Spring来创建对象

在Spring中,通过配置文件beans.xml来创建对象,通常来说一个类对应一个bean。

1
2
3
4
5
6
<bean id="userDao" class="com.xliu.dao.UserDaoImpl"/>
<bean id="userDaoMysql" class="com.xliu.dao.UserDaoMysqlImpl"/>

<bean id="userServiceImpl" class="com.xliu.service.UserServiceImpl">
<property name="userDao" ref="userDaoMysql"/>
</bean>

id = 变量名

class = new的对象

property相当于给对象中的属性设置一个值,只要有一个属性,就写一个来赋值

因为在com.xliu.service.UserServiceImpl这个类中,有setUserDao这个方法,因此name=”userDao”, ref=”userDaoMysql”代表的是创建对象的类,ref的值对应bean的id。

MyTest

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import com.xliu.dao.UserDao;
import com.xliu.dao.UserDaoImpl;
import com.xliu.dao.UserDaoMysqlImpl;
import com.xliu.service.UserService;
import com.xliu.service.UserServiceImpl;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Mytest {
public static void main(String[] args) {
// 获取Spring的上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 我们的对象现在都在Spring中管理了,我们要使用,直接去里面取出来就可以了
UserServiceImpl userService = (UserServiceImpl) context.getBean("userServiceImpl");
userService.getUser();
}
}

输出:MySQL获取用户数据

分析

如果需要使用别的UserDao实现类,只需要在配置文件中改ref的值,例如ref="userDao",即可输出获取用户数据

Spring Note 3

Posted on 2020-03-28 Edited on 2020-03-29

UserDao userdao = new UserDaoImpl();

UserDao is an interface class, UserDaoImpl is its implementation class. This code can also be replaced by UserDaoImpl userdaoimpl = new UserDaoImpl(), but why we don’t do so?

This is about the polymorphism. Knowing an interface can be implemented many times, imaging another implementation is provided and will be used, we name it UserDaoMySQLImpl. If I want to call this class in service layer, I have to rewrite as userDaoMySQLImpl userdaomysqlimpl = new UserDaoMySQLImpl(). If I use the code UserDao userdao = new UserDaoImpl(), I only have to change the new UserDaoImpl() to new UserDaoMySQLImpl().

After comparing these two codes, I can easily find the use of interface and can feel the sense of polymorphism.

MySQL笔记:基础

Posted on 2020-03-25 Edited on 2020-03-28

SHOW

输入:
SHOW COLUMNS FROM customers;
DESCRIBE customers;
输出:

Field Type Null Key Default Extra
cust_id int(11) NO PRI NULL auto_increment
cust_name char(50) NO NULL
cust_address char(50) YES NULL
cust_city char(50) YES NULL
cust_state char(5) YES NULL
cust_zip char(10) YES NULL
cust_country char(50) YES NULL
cust_contact char(50) YES NULL
cust_email char(255) YES NULL

SHOW COLUMNS 返回表的信息,包括字段名、数据类型等,与DESCRIBE等价。

  • SHOW STATUS:显示广泛的服务器状态信息;
  • SHOW CREATE DATABSE,SHOW CREATE TABLE:显示创建特定数据库或表的MySQL语句
  • SHOW GRANTS:显示授予用户(所有用户或特定用户)的安全权限
  • SHOW ERRORS,SHOW WARNINGS:显示服务器错误或警告消息

    SELECT

    SELECT prod_name FROM products;:products表中名为prod_name的列
    SELECT prod_id,prod_name,prod_price FROM products;:products表中指定的3列
    SELECT * FROM products;:通配符(*)返回表中所有列
    SELECT DISTINCT vend_id FROM products;:DISTINCT只返回不同的值,如果ven_id中有重复的会被省略
    SELECT prod_name FROM products LIMIT 5;:LIMIT 5指示返回不多于5行
    SELECT prod_name FROM products LIMIT 5,3;:从第5行开始再输出3行

    排序

    SELECT prod_name FROM products ORDER BY prod_name;:对prod_name列以字母顺序排序
    SELECT prod_id, prod_price, prod_name FROM products ORDER BY prod_price, prod_name;:当多个行具有相同的prod_price值时才对产品按prod_name进行排序。
    SELECT prod+id, prod_price, prod_name FROM products ORDER BY prod_price DESC:DESC指定prod_price降序排序
    SELECT prod+id, prod_price, prod_name FROM products ORDER BY prod_price DESC
1…567…12
Feb 1997

Feb 1997

112 posts
4 categories
24 tags
© 2020 Feb 1997